/**
 * Constructor Context
 *
 * Provides centralized state management for the tour constructor page.
 * This reduces prop drilling by making constructor state available to
 * deeply nested components.
 *
 * Components can access constructor state via:
 * - useConstructorContext() - throws if used outside provider
 * - useConstructorContextOptional() - returns null if outside provider
 */

import React, {
  createContext,
  useContext,
  useMemo,
  type ReactNode,
} from 'react';
import type {
  CanvasElement,
  CanvasElementType,
  PageBackgroundState,
  PageBackgroundVideoSettings,
  EditorMenuItem,
  EditorTab,
  GalleryCard,
  GalleryInfoSpan,
  CarouselSlide,
  AssetOption,
} from '../types/constructor';
import type { TourPage, Asset } from '../types/entities';

// ============================================================================
// Navigation Types
// ============================================================================

export type NavigationElementType = Extract<
  CanvasElementType,
  'navigation_next' | 'navigation_prev'
>;

// ============================================================================
// Gallery/Carousel Operations
// ============================================================================

export interface GalleryCardOperations {
  add: () => void;
  update: (cardId: string, patch: Partial<GalleryCard>) => void;
  remove: (cardId: string) => void;
}

export interface GalleryInfoSpanOperations {
  add: () => void;
  update: (spanId: string, patch: Partial<GalleryInfoSpan>) => void;
  remove: (spanId: string) => void;
}

export interface CarouselSlideOperations {
  add: () => void;
  update: (slideId: string, patch: Partial<CarouselSlide>) => void;
  remove: (slideId: string) => void;
}

// ============================================================================
// Transition Creation State
// ============================================================================

export interface TransitionCreationState {
  name: string;
  videoUrl: string;
  supportsReverse: boolean;
  isCreating: boolean;
}

export interface TransitionCreationActions {
  setName: (name: string) => void;
  setVideoUrl: (url: string) => void;
  setSupportsReverse: (value: boolean) => void;
  create: () => void;
}

// ============================================================================
// Context Types
// ============================================================================

export interface ConstructorContextValue {
  // Project state
  projectId: string;

  // Page state
  pages: TourPage[];
  activePageId: string | null;
  activePage: TourPage | null;
  setActivePageId: (id: string) => void;

  // Background state (consolidated from 8 useState hooks)
  pageBackground: PageBackgroundState;
  setPageBackground: React.Dispatch<React.SetStateAction<PageBackgroundState>>;
  updateBackgroundFromPage: (page: TourPage | null) => void;

  // Background convenience setters
  setBackgroundImageUrl: (url: string) => void;
  setBackgroundVideoUrl: (url: string) => void;
  setBackgroundAudioUrl: (url: string) => void;
  setBackgroundVideoSettings: (
    settings: Partial<PageBackgroundVideoSettings>,
  ) => void;

  // Element state
  elements: CanvasElement[];
  setElements: React.Dispatch<React.SetStateAction<CanvasElement[]>>;
  selectedElementId: string | null;
  selectedElement: CanvasElement | null;
  selectElement: (id: string) => void;
  clearSelection: () => void;
  updateElement: (id: string, patch: Partial<CanvasElement>) => void;
  removeElement: (id: string) => void;
  updateSelectedElement: (patch: Partial<CanvasElement>) => void;
  removeSelectedElement: () => void;

  // Menu state
  selectedMenuItem: EditorMenuItem;
  setSelectedMenuItem: (item: EditorMenuItem) => void;
  isMenuOpen: boolean;
  setIsMenuOpen: (open: boolean) => void;

  // Editor state
  elementEditorTab: EditorTab;
  setElementEditorTab: (tab: EditorTab) => void;

  // Assets (cached via React Query)
  assets: Asset[];
  isLoadingAssets: boolean;

  // Asset options (derived from assets)
  assetOptions: {
    image: AssetOption[];
    backgroundImage: AssetOption[];
    video: AssetOption[];
    audio: AssetOption[];
    transitionVideo: AssetOption[];
    icon: AssetOption[];
  };

  // Gallery/Carousel operations
  galleryCards: GalleryCardOperations;
  galleryInfoSpans: GalleryInfoSpanOperations;
  carouselSlides: CarouselSlideOperations;

  // Duration resolver
  getDuration: (url: string) => number | undefined;

  // Duration notes (derived from getDuration)
  durationNotes: {
    backgroundVideo: string;
    backgroundAudio: string;
    selectedMedia: string;
    selectedTransition: string;
    newTransition: string;
  };

  // Transition preview
  onPreviewTransition: (direction: 'forward' | 'back') => void;

  // Transition creation
  transitionCreation: TransitionCreationState & TransitionCreationActions;

  // Navigation settings
  allowedNavigationTypes: NavigationElementType[];
  normalizeNavigationType: (
    element: CanvasElement,
    nextType: NavigationElementType,
  ) => CanvasElement;

  // Actions
  save: () => Promise<void>;
  isSaving: boolean;
}

// ============================================================================
// Context Creation
// ============================================================================

const ConstructorContext = createContext<ConstructorContextValue | null>(null);

// ============================================================================
// Provider Props
// ============================================================================

export interface ConstructorProviderProps {
  children: ReactNode;
  value: ConstructorContextValue;
}

// ============================================================================
// Provider Component
// ============================================================================

export function ConstructorProvider({
  children,
  value,
}: ConstructorProviderProps) {
  return (
    <ConstructorContext.Provider value={value}>
      {children}
    </ConstructorContext.Provider>
  );
}

// ============================================================================
// Hooks
// ============================================================================

/**
 * Access constructor context (throws if used outside provider)
 */
export function useConstructorContext(): ConstructorContextValue {
  const context = useContext(ConstructorContext);
  if (!context) {
    throw new Error(
      'useConstructorContext must be used within a ConstructorProvider',
    );
  }
  return context;
}

/**
 * Access constructor context (returns null if outside provider)
 */
export function useConstructorContextOptional(): ConstructorContextValue | null {
  return useContext(ConstructorContext);
}

// ============================================================================
// Selector Hooks (for performance optimization)
// ============================================================================

/**
 * Select only pages-related state to minimize re-renders
 */
export function useConstructorPages() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      pages: ctx.pages,
      activePageId: ctx.activePageId,
      activePage: ctx.activePage,
      setActivePageId: ctx.setActivePageId,
    }),
    [ctx.pages, ctx.activePageId, ctx.activePage, ctx.setActivePageId],
  );
}

/**
 * Select only elements-related state
 */
export function useConstructorElements() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      elements: ctx.elements,
      setElements: ctx.setElements,
      selectedElementId: ctx.selectedElementId,
      selectedElement: ctx.selectedElement,
      selectElement: ctx.selectElement,
      clearSelection: ctx.clearSelection,
      updateElement: ctx.updateElement,
      removeElement: ctx.removeElement,
      updateSelectedElement: ctx.updateSelectedElement,
      removeSelectedElement: ctx.removeSelectedElement,
    }),
    [
      ctx.elements,
      ctx.setElements,
      ctx.selectedElementId,
      ctx.selectedElement,
      ctx.selectElement,
      ctx.clearSelection,
      ctx.updateElement,
      ctx.removeElement,
      ctx.updateSelectedElement,
      ctx.removeSelectedElement,
    ],
  );
}

/**
 * Select only background-related state
 */
export function useConstructorBackground() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      pageBackground: ctx.pageBackground,
      setPageBackground: ctx.setPageBackground,
      updateBackgroundFromPage: ctx.updateBackgroundFromPage,
      setBackgroundImageUrl: ctx.setBackgroundImageUrl,
      setBackgroundVideoUrl: ctx.setBackgroundVideoUrl,
      setBackgroundAudioUrl: ctx.setBackgroundAudioUrl,
      setBackgroundVideoSettings: ctx.setBackgroundVideoSettings,
    }),
    [
      ctx.pageBackground,
      ctx.setPageBackground,
      ctx.updateBackgroundFromPage,
      ctx.setBackgroundImageUrl,
      ctx.setBackgroundVideoUrl,
      ctx.setBackgroundAudioUrl,
      ctx.setBackgroundVideoSettings,
    ],
  );
}

/**
 * Select only assets-related state
 */
export function useConstructorAssets() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      assets: ctx.assets,
      isLoadingAssets: ctx.isLoadingAssets,
      assetOptions: ctx.assetOptions,
    }),
    [ctx.assets, ctx.isLoadingAssets, ctx.assetOptions],
  );
}

/**
 * Select gallery/carousel operations
 */
export function useConstructorCollectionOps() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      galleryCards: ctx.galleryCards,
      galleryInfoSpans: ctx.galleryInfoSpans,
      carouselSlides: ctx.carouselSlides,
    }),
    [ctx.galleryCards, ctx.galleryInfoSpans, ctx.carouselSlides],
  );
}

/**
 * Select duration utilities
 */
export function useConstructorDuration() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      getDuration: ctx.getDuration,
      durationNotes: ctx.durationNotes,
    }),
    [ctx.getDuration, ctx.durationNotes],
  );
}

/**
 * Select transition creation state
 */
export function useConstructorTransitionCreation() {
  const ctx = useConstructorContext();
  return ctx.transitionCreation;
}

/**
 * Select navigation settings
 */
export function useConstructorNavigation() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      pages: ctx.pages,
      activePageId: ctx.activePageId,
      allowedNavigationTypes: ctx.allowedNavigationTypes,
      normalizeNavigationType: ctx.normalizeNavigationType,
      onPreviewTransition: ctx.onPreviewTransition,
    }),
    [
      ctx.pages,
      ctx.activePageId,
      ctx.allowedNavigationTypes,
      ctx.normalizeNavigationType,
      ctx.onPreviewTransition,
    ],
  );
}

/**
 * Select editor menu state
 */
export function useConstructorMenu() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      selectedMenuItem: ctx.selectedMenuItem,
      setSelectedMenuItem: ctx.setSelectedMenuItem,
      isMenuOpen: ctx.isMenuOpen,
      setIsMenuOpen: ctx.setIsMenuOpen,
    }),
    [
      ctx.selectedMenuItem,
      ctx.setSelectedMenuItem,
      ctx.isMenuOpen,
      ctx.setIsMenuOpen,
    ],
  );
}

/**
 * Select editor tab state
 */
export function useConstructorEditorTab() {
  const ctx = useConstructorContext();
  return useMemo(
    () => ({
      activeTab: ctx.elementEditorTab,
      setActiveTab: ctx.setElementEditorTab,
    }),
    [ctx.elementEditorTab, ctx.setElementEditorTab],
  );
}

export default ConstructorContext;
