import React, {
  createContext,
  useContext,
  useState,
  ReactNode,
  useRef,
  useCallback,
} from 'react';
import { useNavigation } from '@app/contexts/NavigationContext';
import { preferencesService, type PdfRenderMode } from '@app/services/preferencesService';
import {
  createViewerActions,
  ScrollActions,
  ZoomActions,
  PanActions,
  SelectionActions,
  SpreadActions,
  RotationActions,
  SearchActions,
  ExportActions,
  BookmarkActions,
  AttachmentActions,
  PrintActions,
} from '@app/contexts/viewer/viewerActions';
import {
  BridgeRef,
  BridgeApiMap,
  BridgeStateMap,
  BridgeKey,
  ViewerBridgeRegistry,
  createBridgeRegistry,
  registerBridge as setBridgeRef,
  ScrollState,
  ZoomState,
  PanState,
  SelectionState,
  SpreadState,
  RotationState,
  SearchState,
  ExportState,
  ThumbnailAPIWrapper,
  BookmarkState,
  AttachmentState,
  DocumentPermissionsState,
  PdfPermissionFlag,
} from '@app/contexts/viewer/viewerBridges';
import { SpreadMode } from '@embedpdf/plugin-spread/react';

function useImmediateNotifier<Args extends unknown[]>() {
  const callbacksRef = useRef(new Set<(...args: Args) => void>());

  const register = useCallback((callback: (...args: Args) => void) => {
    callbacksRef.current.add(callback);
    return () => {
      callbacksRef.current.delete(callback);
    };
  }, []);

  const trigger = useCallback((...args: Args) => {
    callbacksRef.current.forEach(cb => {
      try {
        cb(...args);
      } catch (error) {
        console.error('Immediate callback error:', error);
      }
    });
  }, []);

  return { register, trigger };
}

/**
 * ViewerContext provides a unified interface to EmbedPDF functionality.
 *
 * Architecture:
 * - Bridges store their own state locally and register with this context
 * - Context provides read-only access to bridge state via getter functions
 * - Actions call EmbedPDF APIs directly through bridge references
 * - No circular dependencies - bridges don't call back into this context
 */
export interface ViewerContextType {
  // UI state managed by this context
  isThumbnailSidebarVisible: boolean;
  toggleThumbnailSidebar: () => void;
  isBookmarkSidebarVisible: boolean;
  toggleBookmarkSidebar: () => void;
  isAttachmentSidebarVisible: boolean;
  toggleAttachmentSidebar: () => void;
  isCommentsSidebarVisible: boolean;
  setCommentsSidebarVisible: (visible: boolean) => void;
  toggleCommentsSidebar: () => void;

  /** Request focus or highlight of a comment card in the sidebar (opens sidebar, then scrolls + flashes or focuses input). */
  highlightCommentRequest: {
    documentId: string;
    pageIndex: number;
    annotationId: string;
    action: 'focus' | 'highlight';
  } | null;
  requestCommentFocus: (documentId: string, pageIndex: number, annotationId: string, hasContent: boolean) => void;
  clearHighlightCommentRequest: () => void;

  // Search interface visibility
  isSearchInterfaceVisible: boolean;
  searchInterfaceActions: {
    open: () => void;
    close: () => void;
    toggle: () => void;
  };

  // Annotation visibility toggle
  isAnnotationsVisible: boolean;
  toggleAnnotationsVisibility: () => void;

  // Annotation/drawing mode for viewer
  isAnnotationMode: boolean;
  setAnnotationMode: (enabled: boolean) => void;

  // Active file index for multi-file viewing
  activeFileIndex: number;
  setActiveFileIndex: (index: number) => void;

  // State getters - read current state from bridges
  getScrollState: () => ScrollState;
  getZoomState: () => ZoomState;
  getPanState: () => PanState;
  getSelectionState: () => SelectionState;
  getSpreadState: () => SpreadState;
  getRotationState: () => RotationState;
  getSearchState: () => SearchState;
  getThumbnailAPI: () => ThumbnailAPIWrapper | null;
  getExportState: () => ExportState;
  getBookmarkState: () => BookmarkState;
  hasBookmarkSupport: () => boolean;
  getAttachmentState: () => AttachmentState;
  hasAttachmentSupport: () => boolean;
  getDocumentPermissions: () => DocumentPermissionsState;
  hasPermission: (flag: PdfPermissionFlag) => boolean;

  // Immediate update callbacks
  registerImmediateZoomUpdate: (callback: (percent: number) => void) => () => void;
  registerImmediateScrollUpdate: (callback: (currentPage: number, totalPages: number) => void) => () => void;
  registerImmediateSpreadUpdate: (callback: (mode: SpreadMode, isDualPage: boolean) => void) => () => void;
  registerImmediatePanUpdate: (callback: (isPanning: boolean) => void) => () => void;

  // Internal - for bridges to trigger immediate updates
  triggerImmediateScrollUpdate: (currentPage: number, totalPages: number) => void;
  triggerImmediateZoomUpdate: (zoomPercent: number) => void;
  triggerImmediateSpreadUpdate: (mode: SpreadMode, isDualPage?: boolean) => void;
  triggerImmediatePanUpdate: (isPanning: boolean) => void;

  // Action handlers - call EmbedPDF APIs directly
  scrollActions: ScrollActions;
  zoomActions: ZoomActions;
  panActions: PanActions;
  selectionActions: SelectionActions;
  spreadActions: SpreadActions;
  rotationActions: RotationActions;
  searchActions: SearchActions;
  exportActions: ExportActions;
  bookmarkActions: BookmarkActions;
  attachmentActions: AttachmentActions;
  printActions: PrintActions;

  // Bridge registration - internal use by bridges
  registerBridge: <K extends BridgeKey>(
    type: K,
    ref: BridgeRef<BridgeStateMap[K], BridgeApiMap[K]> | null
  ) => void;

  // Save changes function - registered by EmbedPdfViewer
  applyChanges: (() => Promise<void>) | null;
  setApplyChanges: (fn: (() => Promise<void>) | null) => void;

  // PDF page color rendering mode (viewer-only, never modifies the PDF)
  pdfRenderMode: PdfRenderMode;
  cyclePdfRenderMode: () => void;
}

export const ViewerContext = createContext<ViewerContextType | null>(null);

interface ViewerProviderProps {
  children: ReactNode;
}

export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
  // UI state - only state directly managed by this context
  const [isThumbnailSidebarVisible, setIsThumbnailSidebarVisible] = useState(false);
  const [isBookmarkSidebarVisible, setIsBookmarkSidebarVisible] = useState(false);
  const [isAttachmentSidebarVisible, setIsAttachmentSidebarVisible] = useState(false);
  const [isCommentsSidebarVisible, setIsCommentsSidebarVisible] = useState(false);
  const [highlightCommentRequest, setHighlightCommentRequest] = useState<{
    documentId: string;
    pageIndex: number;
    annotationId: string;
    action: 'focus' | 'highlight';
  } | null>(null);
  const [isSearchInterfaceVisible, setSearchInterfaceVisible] = useState(false);
  const [isAnnotationsVisible, setIsAnnotationsVisible] = useState(true);
  const [isAnnotationMode, setIsAnnotationModeState] = useState(false);
  const [activeFileIndex, setActiveFileIndex] = useState(0);
  const [pdfRenderMode, setPdfRenderModeState] = useState<PdfRenderMode>(
    () => preferencesService.getPreference('pdfRenderMode')
  );

  // Get current navigation state to check if we're in sign mode
  useNavigation();

  // Bridge registry - bridges register their state and APIs here
  const bridgeRefs = useRef<ViewerBridgeRegistry>(createBridgeRegistry());

  // Apply changes function - registered by EmbedPdfViewer
  const applyChangesRef = useRef<(() => Promise<void>) | null>(null);

  const setApplyChanges = useCallback((fn: (() => Promise<void>) | null) => {
    applyChangesRef.current = fn;
  }, []);

  const applyChanges = useCallback(async () => {
    if (applyChangesRef.current) {
      await applyChangesRef.current();
    }
  }, []);

  const {
    register: registerImmediateZoomUpdate,
    trigger: triggerImmediateZoomInternal,
  } = useImmediateNotifier<[number]>();
  const {
    register: registerImmediateScrollUpdate,
    trigger: triggerImmediateScrollInternal,
  } = useImmediateNotifier<[number, number]>();
  const {
    register: registerImmediateSpreadUpdate,
    trigger: triggerImmediateSpreadInternal,
  } = useImmediateNotifier<[SpreadMode, boolean]>();
  const {
    register: registerImmediatePanUpdate,
    trigger: triggerImmediatePanInternal,
  } = useImmediateNotifier<[boolean]>();

  const triggerImmediateZoomUpdate = useCallback(
    (percent: number) => {
      triggerImmediateZoomInternal(percent);
    },
    [triggerImmediateZoomInternal]
  );

  const triggerImmediateScrollUpdate = useCallback(
    (currentPage: number, totalPages: number) => {
      triggerImmediateScrollInternal(currentPage, totalPages);
    },
    [triggerImmediateScrollInternal]
  );

  const triggerImmediateSpreadUpdate = useCallback(
    (mode: SpreadMode, isDualPage: boolean = mode !== SpreadMode.None) => {
      triggerImmediateSpreadInternal(mode, isDualPage);
    },
    [triggerImmediateSpreadInternal]
  );

  const triggerImmediatePanUpdate = useCallback(
    (isPanning: boolean) => {
      triggerImmediatePanInternal(isPanning);
    },
    [triggerImmediatePanInternal]
  );

  const registerBridge = useCallback(
    <K extends BridgeKey>(
      type: K,
      ref: BridgeRef<BridgeStateMap[K], BridgeApiMap[K]> | null
    ) => {
      setBridgeRef(bridgeRefs.current, type, ref);
    },
    []
  );

  const toggleThumbnailSidebar = () => {
    setIsThumbnailSidebarVisible(prev => !prev);
  };

  const toggleBookmarkSidebar = () => {
    setIsBookmarkSidebarVisible(prev => !prev);
  };

  const toggleAttachmentSidebar = () => {
    setIsAttachmentSidebarVisible(prev => !prev);
  };

  const setCommentsSidebarVisible = (visible: boolean) => {
    setIsCommentsSidebarVisible(visible);
  };

  const toggleCommentsSidebar = () => {
    setIsCommentsSidebarVisible(prev => !prev);
  };

  const requestCommentFocus = useCallback(
    (documentId: string, pageIndex: number, annotationId: string, hasContent: boolean) => {
      setIsCommentsSidebarVisible(true);
      setHighlightCommentRequest({
        documentId,
        pageIndex,
        annotationId,
        action: hasContent ? 'highlight' : 'focus',
      });
    },
    []
  );

  const clearHighlightCommentRequest = useCallback(() => {
    setHighlightCommentRequest(null);
  }, []);

  const searchInterfaceActions = {
    open: () => setSearchInterfaceVisible(true),
    close: () => setSearchInterfaceVisible(false),
    toggle: () => setSearchInterfaceVisible(prev => !prev),
  };

  const toggleAnnotationsVisibility = () => {
    setIsAnnotationsVisible(prev => !prev);
  };

  const setAnnotationMode = (enabled: boolean) => {
    setIsAnnotationModeState(enabled);
  };

  const cyclePdfRenderMode = useCallback(() => {
    setPdfRenderModeState(prev => {
      const next: PdfRenderMode =
        prev === 'normal' ? 'dark' : prev === 'dark' ? 'sepia' : 'normal';
      preferencesService.setPreference('pdfRenderMode', next);
      return next;
    });
  }, []);

  // State getters - read from bridge refs
  const getScrollState = (): ScrollState => {
    return bridgeRefs.current.scroll?.state || { currentPage: 1, totalPages: 0 };
  };

  const getZoomState = (): ZoomState => {
    return bridgeRefs.current.zoom?.state || { currentZoom: 1.4, zoomPercent: 140 };
  };

  const getPanState = (): PanState => {
    return bridgeRefs.current.pan?.state || { isPanning: false };
  };

  const getSelectionState = (): SelectionState => {
    return bridgeRefs.current.selection?.state || { hasSelection: false };
  };

  const getSpreadState = (): SpreadState => {
    return bridgeRefs.current.spread?.state || { spreadMode: SpreadMode.None, isDualPage: false };
  };

  const getRotationState = (): RotationState => {
    return bridgeRefs.current.rotation?.state || { rotation: 0 };
  };

  const getSearchState = (): SearchState => {
    return bridgeRefs.current.search?.state || { results: null, activeIndex: 0 };
  };

  const getThumbnailAPI = () => {
    return bridgeRefs.current.thumbnail?.api || null;
  };

  const getExportState = (): ExportState => {
    return bridgeRefs.current.export?.state || { canExport: false };
  };

  const getBookmarkState = (): BookmarkState => {
    return (
      bridgeRefs.current.bookmark?.state || {
        bookmarks: null,
        isLoading: false,
        error: null,
      }
    );
  };

  const hasBookmarkSupport = () => Boolean(bridgeRefs.current.bookmark);

  const getAttachmentState = (): AttachmentState => {
    return (
      bridgeRefs.current.attachment?.state || {
        attachments: null,
        isLoading: false,
        error: null,
      }
    );
  };

  const hasAttachmentSupport = () => Boolean(bridgeRefs.current.attachment);

  const getDocumentPermissions = (): DocumentPermissionsState => {
    return bridgeRefs.current.permissions?.state || {
      isEncrypted: false,
      isOwnerUnlocked: false,
      permissions: PdfPermissionFlag.AllowAll,
      canPrint: true,
      canModifyContents: true,
      canCopyContents: true,
      canModifyAnnotations: true,
      canFillForms: true,
      canExtractForAccessibility: true,
      canAssembleDocument: true,
      canPrintHighQuality: true,
    };
  };

  const hasPermission = (flag: PdfPermissionFlag): boolean => {
    const api = bridgeRefs.current.permissions?.api;
    if (api?.hasPermission) {
      return api.hasPermission(flag);
    }
    // Default: allow all permissions - warn in development
    if (process.env.NODE_ENV === 'development') {
      console.warn('[ViewerContext] Permissions API not available, defaulting to allow');
    }
    return true;
  };

  // Action handlers - call APIs directly
  const {
    scrollActions,
    zoomActions,
    panActions,
    selectionActions,
    spreadActions,
    rotationActions,
    searchActions,
    exportActions,
    bookmarkActions,
    attachmentActions,
    printActions,
  } = createViewerActions({
    registry: bridgeRefs,
    getScrollState,
    getZoomState,
    triggerImmediateZoomUpdate,
  });

  const value: ViewerContextType = {
    // UI state
    isThumbnailSidebarVisible,
    toggleThumbnailSidebar,
    isBookmarkSidebarVisible,
    toggleBookmarkSidebar,
    isAttachmentSidebarVisible,
    toggleAttachmentSidebar,
    isCommentsSidebarVisible,
    setCommentsSidebarVisible,
    toggleCommentsSidebar,
    highlightCommentRequest,
    requestCommentFocus,
    clearHighlightCommentRequest,

    // Search interface
    isSearchInterfaceVisible,
    searchInterfaceActions,

    // Annotation controls
    isAnnotationsVisible,
    toggleAnnotationsVisibility,
    isAnnotationMode,
    setAnnotationMode,

    // Active file index
    activeFileIndex,
    setActiveFileIndex,

    // State getters
    getScrollState,
    getZoomState,
    getPanState,
    getSelectionState,
    getSpreadState,
    getRotationState,
    getSearchState,
    getThumbnailAPI,
    getExportState,
    getBookmarkState,
    hasBookmarkSupport,
    getAttachmentState,
    hasAttachmentSupport,
    getDocumentPermissions,
    hasPermission,

    // Immediate updates
    registerImmediateZoomUpdate,
    registerImmediateScrollUpdate,
    registerImmediateSpreadUpdate,
    registerImmediatePanUpdate,
    triggerImmediateScrollUpdate,
    triggerImmediateZoomUpdate,
    triggerImmediateSpreadUpdate,
    triggerImmediatePanUpdate,

    // Actions
    scrollActions,
    zoomActions,
    panActions,
    selectionActions,
    spreadActions,
    rotationActions,
    searchActions,
    exportActions,
    bookmarkActions,
    attachmentActions,
    printActions,

    // Bridge registration
    registerBridge,

    // Apply changes
    applyChanges,
    setApplyChanges,

    // PDF page rendering mode
    pdfRenderMode,
    cyclePdfRenderMode,
  };

  return (
    <ViewerContext.Provider value={value}>
      {children}
    </ViewerContext.Provider>
  );
};

export const useViewer = (): ViewerContextType => {
  const context = useContext(ViewerContext);
  if (!context) {
    throw new Error('useViewer must be used within a ViewerProvider');
  }
  return context;
};
