/**
 * useNeighborGraph Hook
 *
 * Builds a navigation graph from page_links to determine which pages
 * are neighbors and should have their assets preloaded.
 */

import { useMemo } from 'react';
import { PRELOAD_CONFIG } from '../config/preload.config';
import type {
  PreloadPage,
  PreloadPageLink,
  PreloadElement,
  PreloadAssetInfo,
  PreloadNeighborInfo,
} from '../types/preload';

interface UseNeighborGraphOptions {
  pages: PreloadPage[];
  pageLinks: PreloadPageLink[];
  elements: PreloadElement[];
  maxDepth?: number;
}

interface NeighborGraphResult {
  /**
   * Get neighboring page IDs within maxDepth hops
   */
  getNeighbors: (
    currentPageId: string,
    maxDepth?: number,
  ) => PreloadNeighborInfo[];

  /**
   * Get all assets that should be preloaded for given pages
   */
  getAssetsForPages: (pageIds: string[]) => PreloadAssetInfo[];

  /**
   * Get prioritized assets for preloading based on current page
   */
  getPrioritizedAssets: (
    currentPageId: string,
    maxDepth?: number,
  ) => PreloadAssetInfo[];

  /**
   * Raw adjacency list for debugging
   */
  adjacencyList: Map<string, string[]>;
}

/**
 * Parse content_json to extract asset URLs
 */
function extractAssetsFromContent(
  contentJson: string | undefined,
  pageId: string,
): PreloadAssetInfo[] {
  if (!contentJson) return [];

  try {
    const content =
      typeof contentJson === 'string' ? JSON.parse(contentJson) : contentJson;

    const assets: PreloadAssetInfo[] = [];

    // Asset URL fields in element content_json
    const urlFields = PRELOAD_CONFIG.assetFields.all as readonly string[];

    const checkObject = (obj: Record<string, unknown>, depth = 0) => {
      if (depth > 5 || !obj || typeof obj !== 'object') return;

      for (const [key, value] of Object.entries(obj)) {
        if (typeof value === 'string' && value && urlFields.includes(key)) {
          // Classify asset type - transition videos get highest priority
          const lowerKey = key.toLowerCase();
          let assetType: 'transition' | 'video' | 'audio' | 'image';
          if (lowerKey.includes('transition')) {
            assetType = 'transition';
          } else if (lowerKey.includes('video')) {
            assetType = 'video';
          } else if (lowerKey.includes('audio')) {
            assetType = 'audio';
          } else {
            assetType = 'image';
          }

          assets.push({
            url: value,
            pageId,
            assetType,
            priority: 0, // Will be calculated later
          });
        } else if (typeof value === 'object' && value !== null) {
          checkObject(value as Record<string, unknown>, depth + 1);
        }
      }
    };

    checkObject(content);
    return assets;
  } catch {
    return [];
  }
}

export function useNeighborGraph(
  options: UseNeighborGraphOptions,
): NeighborGraphResult {
  const {
    pages,
    pageLinks,
    elements,
    maxDepth = PRELOAD_CONFIG.neighborGraph.maxDepth,
  } = options;

  // Build adjacency list from page links
  const adjacencyList = useMemo(() => {
    const adj = new Map<string, string[]>();

    // Initialize all pages
    pages.forEach((page) => {
      adj.set(page.id, []);
    });

    // Add edges from active page links
    const activeLinks = pageLinks.filter((link) => link.is_active !== false);

    activeLinks.forEach((link) => {
      if (link.from_pageId && link.to_pageId) {
        const neighbors = adj.get(link.from_pageId) || [];
        if (!neighbors.includes(link.to_pageId)) {
          neighbors.push(link.to_pageId);
          adj.set(link.from_pageId, neighbors);
        }
      }
    });

    return adj;
  }, [pages, pageLinks]);

  // BFS to find neighbors within depth
  const getNeighbors = useMemo(() => {
    return (currentPageId: string, depth = maxDepth): PreloadNeighborInfo[] => {
      const visited = new Set<string>();
      const result: PreloadNeighborInfo[] = [];
      const queue: { pageId: string; distance: number }[] = [
        { pageId: currentPageId, distance: 0 },
      ];

      visited.add(currentPageId);

      while (queue.length > 0) {
        const item = queue.shift();
        if (!item) break;
        const { pageId, distance } = item;

        if (distance > 0) {
          result.push({ pageId, distance });
        }

        if (distance < depth) {
          const neighbors = adjacencyList.get(pageId) || [];
          for (const neighborId of neighbors) {
            if (!visited.has(neighborId)) {
              visited.add(neighborId);
              queue.push({ pageId: neighborId, distance: distance + 1 });
            }
          }
        }
      }

      // Sort by distance (closest first)
      return result.sort((a, b) => a.distance - b.distance);
    };
  }, [adjacencyList, maxDepth]);

  // Get assets for a set of pages
  const getAssetsForPages = useMemo(() => {
    return (pageIds: string[]): PreloadAssetInfo[] => {
      const assets: PreloadAssetInfo[] = [];
      const seenUrls = new Set<string>();

      pageIds.forEach((pageId) => {
        // Get elements for this page
        const pageElements = elements.filter((el) => el.pageId === pageId);

        // Extract assets from element content
        pageElements.forEach((element) => {
          const elementAssets = extractAssetsFromContent(
            element.content_json,
            pageId,
          );
          elementAssets.forEach((asset) => {
            if (!seenUrls.has(asset.url)) {
              seenUrls.add(asset.url);
              assets.push(asset);
            }
          });
        });
      });

      // Add transition videos (transition is eagerly loaded in page_links)
      const matchingLinks = pageLinks.filter(
        (link) =>
          link.is_active !== false && pageIds.includes(link.from_pageId || ''),
      );

      matchingLinks.forEach((link) => {
        const videoUrl = link.transition?.video_url;
        if (videoUrl && !seenUrls.has(videoUrl)) {
          seenUrls.add(videoUrl);
          assets.push({
            url: videoUrl,
            pageId: link.from_pageId || '',
            assetType: 'transition',
            priority: 0,
          });
        }
      });

      return assets;
    };
  }, [elements, pageLinks]);

  // Get prioritized assets for preloading
  const getPrioritizedAssets = useMemo(() => {
    return (currentPageId: string, depth = maxDepth): PreloadAssetInfo[] => {
      // Get current page assets (highest priority)
      const currentPageAssets = getAssetsForPages([currentPageId]).map(
        (asset) => ({
          ...asset,
          priority:
            PRELOAD_CONFIG.priority.currentPage +
            (PRELOAD_CONFIG.priority.assetType[asset.assetType] || 0),
        }),
      );

      // Get neighbor page assets
      const neighbors = getNeighbors(currentPageId, depth);
      const neighborAssets: PreloadAssetInfo[] = [];

      neighbors.forEach(({ pageId, distance }) => {
        const assets = getAssetsForPages([pageId]);
        assets.forEach((asset) => {
          const basePriority = PRELOAD_CONFIG.priority.neighborBase / distance;
          const typePriority =
            PRELOAD_CONFIG.priority.assetType[asset.assetType] || 0;

          neighborAssets.push({
            ...asset,
            priority: basePriority + typePriority,
          });
        });
      });

      // Combine and sort by priority (highest first)
      const allAssets = [...currentPageAssets, ...neighborAssets];

      // Deduplicate by URL, keeping highest priority
      const urlToPriority = new Map<string, PreloadAssetInfo>();
      allAssets.forEach((asset) => {
        const existing = urlToPriority.get(asset.url);
        if (!existing || asset.priority > existing.priority) {
          urlToPriority.set(asset.url, asset);
        }
      });

      return Array.from(urlToPriority.values()).sort(
        (a, b) => b.priority - a.priority,
      );
    };
  }, [getAssetsForPages, getNeighbors, maxDepth]);

  return {
    getNeighbors,
    getAssetsForPages,
    getPrioritizedAssets,
    adjacencyList,
  };
}
