/**
 * extractPageLinks Utility
 *
 * Extracts synthetic page links and preload elements from tour pages' ui_schema_json.
 * Used by both constructor and RuntimePresentation for consistent preload behavior.
 */

import { PRELOAD_CONFIG } from '../config/preload.config';
import type { PreloadPageLink, PreloadElement } from '../types/preload';

interface PageWithSchema {
  id: string;
  slug?: string;
  ui_schema_json?: string | Record<string, unknown>;
}

interface ExtractResult {
  pageLinks: PreloadPageLink[];
  preloadElements: PreloadElement[];
}

/**
 * Extract asset URL fields from an element using PRELOAD_CONFIG.
 * Returns an object with all asset fields found in the element.
 */
function extractAssetFields(
  element: Record<string, unknown>,
): Record<string, unknown> {
  const {
    all: allFields,
    nested: nestedFields,
    nestedUrlFields,
  } = PRELOAD_CONFIG.assetFields;
  const contentObj: Record<string, unknown> = {};

  // Extract top-level asset fields
  (allFields as readonly string[]).forEach((field) => {
    const value = element[field];
    if (value !== undefined && value !== '') {
      contentObj[field] = value;
    }
  });

  // Extract nested fields (e.g., galleryCards, carouselSlides)
  (nestedFields as readonly string[]).forEach((field) => {
    const nested = element[field];
    if (Array.isArray(nested)) {
      // Extract URLs from nested items
      const filteredNested = nested
        .map((item: Record<string, unknown>) => {
          const nestedContent: Record<string, unknown> = {};
          (nestedUrlFields as readonly string[]).forEach((urlField) => {
            if (item[urlField] !== undefined && item[urlField] !== '') {
              nestedContent[urlField] = item[urlField];
            }
          });
          return Object.keys(nestedContent).length > 0 ? nestedContent : null;
        })
        .filter(Boolean);
      if (filteredNested.length > 0) {
        contentObj[field] = filteredNested;
      }
    }
  });

  return contentObj;
}

/**
 * Parse ui_schema_json safely.
 */
function parseUiSchema(
  uiSchemaJson: string | Record<string, unknown> | undefined,
): Record<string, unknown> | null {
  if (!uiSchemaJson) return null;
  try {
    return typeof uiSchemaJson === 'string'
      ? JSON.parse(uiSchemaJson)
      : uiSchemaJson;
  } catch {
    return null;
  }
}

/**
 * Extract page links and preload elements from pages' ui_schema_json.
 *
 * This builds:
 * 1. Synthetic page links for the neighbor graph (enables preloading of connected pages)
 * 2. Preload elements with asset URLs for the preload queue
 *
 * @param pages - Array of pages with ui_schema_json
 * @param allPages - Optional: all pages for slug-to-id resolution. If not provided, uses `pages`.
 * @returns Object with pageLinks and preloadElements arrays
 *
 * @example
 * const { pageLinks, preloadElements } = extractPageLinksAndElements(pages);
 * const preloadOrchestrator = usePreloadOrchestrator({
 *   pages,
 *   pageLinks,
 *   elements: preloadElements,
 *   currentPageId,
 * });
 */
export function extractPageLinksAndElements(
  pages: PageWithSchema[],
  allPages?: PageWithSchema[],
): ExtractResult {
  const pagesForLookup = allPages || pages;
  const pageLinks: PreloadPageLink[] = [];
  const preloadElements: PreloadElement[] = [];

  // Build slug-to-id map for resolving targetPageSlug
  const slugToIdMap = new Map<string, string>();
  pagesForLookup.forEach((page) => {
    if (page.slug) {
      slugToIdMap.set(page.slug, page.id);
    }
  });

  pages.forEach((page) => {
    const uiSchema = parseUiSchema(page.ui_schema_json);
    if (!uiSchema) return;

    const pageElements = Array.isArray(uiSchema.elements)
      ? (uiSchema.elements as Record<string, unknown>[])
      : [];

    pageElements.forEach((el) => {
      // Build preload element with asset URLs
      const contentObj = extractAssetFields(el);
      if (Object.keys(contentObj).length > 0) {
        preloadElements.push({
          id:
            String(el.id || '') ||
            `element-${page.id}-${Math.random().toString(36).slice(2)}`,
          pageId: page.id,
          element_type: String(el.type || ''),
          content_json: JSON.stringify(contentObj),
        });
      }

      // Build synthetic page link for navigation elements
      const targetSlug =
        el.targetPageSlug && typeof el.targetPageSlug === 'string'
          ? el.targetPageSlug
          : '';
      const legacyTargetId =
        el.targetPageId && typeof el.targetPageId === 'string'
          ? el.targetPageId
          : '';

      // Resolve slug to page ID (prefer slug, fall back to legacy ID)
      let resolvedTargetPageId = '';
      if (targetSlug) {
        resolvedTargetPageId = slugToIdMap.get(targetSlug) || '';
      } else if (legacyTargetId) {
        // Legacy: targetPageId might be a slug or an ID
        resolvedTargetPageId =
          slugToIdMap.get(legacyTargetId) || legacyTargetId;
      }

      if (resolvedTargetPageId && resolvedTargetPageId !== page.id) {
        pageLinks.push({
          id: `synthetic-${page.id}-${el.id || preloadElements.length}`,
          from_pageId: page.id,
          to_pageId: resolvedTargetPageId,
          is_active: true,
          transition:
            el.transitionVideoUrl && typeof el.transitionVideoUrl === 'string'
              ? {
                  id: `transition-${el.id || preloadElements.length}`,
                  video_url: el.transitionVideoUrl,
                }
              : undefined,
        });
      }
    });
  });

  return { pageLinks, preloadElements };
}
