/**
 * usePageDataLoader Hook
 *
 * Unified hook for loading project and page data in presentation components.
 * Used by both RuntimePresentation (public) and constructor.tsx (authenticated).
 *
 * Features:
 * - Loads project by slug or ID
 * - Loads pages filtered by environment
 * - Sorts pages by sort_order
 * - Handles loading and error states
 * - Supports reloading with page preservation
 */

import { useState, useCallback, useEffect, useMemo } from 'react';
import axios from 'axios';
import { logger } from '../lib/logger';
import type { RuntimeProject, RuntimePage } from '../types/runtime';

/**
 * Configuration for the page data loader
 */
export interface UsePageDataLoaderOptions {
  /** Project ID for authenticated mode (constructor) */
  projectId?: string;
  /** Project slug for public mode (runtime) */
  projectSlug?: string;
  /** Environment to filter pages by */
  environment: 'dev' | 'stage' | 'production';
  /** Whether the data loading should be enabled */
  enabled?: boolean;
  /** Custom API headers (e.g., for runtime environment context) */
  apiHeaders?: Record<string, string>;
  /** Initial page ID from route (for constructor) */
  initialPageId?: string;
}

/**
 * Result of the page data loader
 */
export interface UsePageDataLoaderResult {
  /** Loaded project data */
  project: RuntimeProject | null;
  /** Loaded and filtered pages */
  pages: RuntimePage[];
  /** Whether data is currently loading */
  isLoading: boolean;
  /** Error message if loading failed */
  error: string;
  /** Reload the data (optionally preserving current page selection) */
  reload: (preservePageId?: string) => Promise<void>;
  /** Initially selected page ID */
  initialPageId: string;
}

/**
 * Extract rows from API response
 */
const getRows = (response: unknown): unknown[] => {
  const data = response as { data?: { rows?: unknown[] } };
  return Array.isArray(data?.data?.rows) ? data.data.rows : [];
};

/**
 * Hook for loading project and page data.
 *
 * @example
 * // Runtime mode (public presentation)
 * const { project, pages, isLoading, error } = usePageDataLoader({
 *   projectSlug: 'my-project',
 *   environment: 'production',
 * });
 *
 * @example
 * // Constructor mode (authenticated)
 * const { project, pages, isLoading, error, reload } = usePageDataLoader({
 *   projectId: 'uuid-here',
 *   environment: 'dev',
 *   enabled: isAuthReady,
 * });
 */
export function usePageDataLoader({
  projectId,
  projectSlug,
  environment,
  enabled = true,
  apiHeaders = {},
  initialPageId: initialPageIdFromProps = '',
}: UsePageDataLoaderOptions): UsePageDataLoaderResult {
  const [project, setProject] = useState<RuntimeProject | null>(null);
  const [pages, setPages] = useState<RuntimePage[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState('');
  const [selectedInitialPageId, setSelectedInitialPageId] = useState('');

  // Memoize API config to prevent unnecessary reloads
  const apiConfig = useMemo(
    () => ({
      headers: apiHeaders,
    }),
    // Serialize headers for comparison
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [JSON.stringify(apiHeaders)],
  );

  /**
   * Load project and pages data
   */
  const loadData = useCallback(
    async (preservePageId?: string) => {
      // Need either projectId or projectSlug
      if (!projectId && !projectSlug) {
        setError('No project identifier provided.');
        setIsLoading(false);
        return;
      }

      if (!enabled) {
        return;
      }

      try {
        setIsLoading(true);
        setError('');

        let foundProject: RuntimeProject | null = null;

        // Load by ID (constructor mode)
        if (projectId) {
          const projectResponse = await axios.get(
            `/projects/${projectId}`,
            apiConfig,
          );
          foundProject = projectResponse.data;
        }
        // Load by slug (runtime mode)
        else if (projectSlug) {
          const projectsResponse = await axios.get('/projects', {
            ...apiConfig,
            params: { slug: projectSlug },
          });

          const projectRows = getRows(projectsResponse) as RuntimeProject[];
          foundProject =
            projectRows.find((p) => p.slug === projectSlug) || null;

          if (!foundProject) {
            setError(`Project "${projectSlug}" not found.`);
            setIsLoading(false);
            return;
          }
        }

        if (!foundProject) {
          setError('Project not found.');
          setIsLoading(false);
          return;
        }

        setProject(foundProject);

        // Load pages for this project
        const pagesParams: Record<string, string> = {
          project: foundProject.id,
        };

        // For constructor mode, also filter by environment in params
        if (projectId) {
          pagesParams.environment = environment;
          pagesParams.limit = '500';
          pagesParams.sort = 'asc';
          pagesParams.field = 'sort_order';
        }

        const pagesResponse = await axios.get('/tour_pages', {
          ...apiConfig,
          params: pagesParams,
        });

        let pageRows = getRows(pagesResponse) as RuntimePage[];

        // For runtime mode, filter by environment client-side
        // (backend may not have environment header support)
        if (projectSlug) {
          pageRows = pageRows.filter((p) => p.environment === environment);
        }

        // Sort by sort_order
        pageRows.sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0));

        setPages(pageRows);

        // Determine initial page
        const preservedPageExists =
          preservePageId && pageRows.some((p) => p.id === preservePageId);
        const defaultPageId = preservedPageExists
          ? preservePageId
          : initialPageIdFromProps ||
            (pageRows.length > 0 ? pageRows[0].id : '');

        setSelectedInitialPageId(defaultPageId);
      } catch (err: unknown) {
        const axiosError = err as {
          response?: { status?: number; data?: { message?: string } };
          message?: string;
        };

        // Handle authentication errors
        if (axiosError?.response?.status === 401) {
          setError('Your session has expired. Please sign in again.');
          logger.error('Unauthorized request during data load');
          return;
        }

        const message =
          axiosError?.response?.data?.message ||
          axiosError?.message ||
          'Failed to load presentation data.';

        logger.error(
          'Failed to load page data:',
          err instanceof Error ? err : { error: err },
        );
        setError(message);
        setPages([]);
      } finally {
        setIsLoading(false);
      }
    },
    [
      projectId,
      projectSlug,
      environment,
      enabled,
      apiConfig,
      initialPageIdFromProps,
    ],
  );

  // Initial load
  useEffect(() => {
    loadData();
  }, [loadData]);

  return {
    project,
    pages,
    isLoading,
    error,
    reload: loadData,
    initialPageId: selectedInitialPageId,
  };
}
