import { useCallback, useEffect, useMemo } from 'react';
import type { ComponentProps, ReactNode } from 'react';
import { SidebarExpandIcon } from '../ui/icons';
import DocumentsPanel from '../documents/panel/DocumentsPanel';
import DocumentViewerPanel from '../preview/DocumentViewerPanel';
import { usePanelManager } from './PanelManagerContext';
import { FolderManagerProvider } from '../folders/FolderManagerContext';
import type { Identifier } from '../types/identifiers';

export type EnsureAssetUrl = (
  docId: Identifier,
  asset: unknown,
  options?: Record<string, unknown>,
) => Promise<unknown> | void;
export type EnsurePreviewData = (docId: Identifier, options?: Record<string, unknown>) => Promise<unknown>;
export type GetDocumentAsset = (document: unknown, assetType: string) => unknown;
export type NotifyApiError = (error: unknown, fallbackMessage?: string) => void;

export type DocumentsTableProps = ComponentProps<typeof DocumentsPanel> | null;
export type DetailPanelProps = (ComponentProps<typeof DocumentViewerPanel> & {
  onClose?: () => void;
  onOpenPreview?: (args: { documentIds: Array<string> }) => void;
  folderNodes?: Map<Identifier | 'root', unknown>;
  ensureFolderData?: (
    folderId: Identifier | 'root',
    options?: { force?: boolean; includeDocuments?: boolean },
  ) => Promise<void>;
}) | null;

export type WorkspaceSurface = { content: ReactNode; detail?: ReactNode | null; detailMode?: 'overlay' | 'inline' | null } | null;

export interface UseWorkspaceSurfaceArgs {
  sidebarHidden?: boolean;
  onExpandSidebar?: () => void;
  documentsTableProps?: DocumentsTableProps;
  detailPanelProps?: DetailPanelProps;
  detailPanelOpen?: boolean;
  previewWorkspaceDocument?: unknown;
  previewDocumentId?: Identifier | null;
  ensureAssetUrl?: EnsureAssetUrl;
  ensurePreviewData?: EnsurePreviewData;
  getDocumentAsset?: GetDocumentAsset;
  notifyApiError?: NotifyApiError;
  closeDocumentPreview?: () => void;
}

export interface UseWorkspaceSurfaceResult {
  surface: WorkspaceSurface;
}

export const useWorkspaceSurface = ({
  sidebarHidden = false,
  onExpandSidebar,
  documentsTableProps,
  detailPanelProps,
  detailPanelOpen = false,
  previewWorkspaceDocument,
  previewDocumentId,
  ensureAssetUrl,
  ensurePreviewData,
  getDocumentAsset,
  notifyApiError,
  closeDocumentPreview,
}: UseWorkspaceSurfaceArgs): UseWorkspaceSurfaceResult => {
  const { registerDetailCloseHandler, setDetailActive } = usePanelManager();

  useEffect(() => {
    const handler = detailPanelProps?.onClose || null;
    registerDetailCloseHandler(handler);
    return () => registerDetailCloseHandler(null);
  }, [registerDetailCloseHandler, detailPanelProps?.onClose]);

  useEffect(() => {
    setDetailActive(Boolean(detailPanelOpen));
    return () => setDetailActive(false);
  }, [detailPanelOpen, setDetailActive]);

  const renderSidebarToggle = useCallback<() => ReactNode>(() => {
    if (!sidebarHidden) {
      return null;
    }
    return (
      <button
        type="button"
        className="icon-button"
        onClick={onExpandSidebar}
        aria-label="Expand sidebar"
        title="Expand sidebar"
      >
        <SidebarExpandIcon />
      </button>
    );
  }, [sidebarHidden, onExpandSidebar]);

  const documentsSurface = useMemo<WorkspaceSurface>(() => {
    if (!documentsTableProps) {
      return null;
    }

    const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
    const viewMode = documentsTableProps.viewMode;
    const sidebarMode = viewMode === 'desk' ? 'overlay' : 'inline';

    const detailMode: 'overlay' | 'inline' | null = detailPanelOpen && detailPanelProps ? sidebarMode : null;
    const detail = detailPanelOpen && detailPanelProps
      ? (() => {
        const {
          onClose,
          onOpenPreview,
          tags: tagOptions,
          folderNodes,
          ensureFolderData,
          ...restDetailProps
        } = detailPanelProps;
        const viewer = (
          <DocumentViewerPanel
            variant="sidebar"
            sidebarMode={sidebarMode}
            onClose={onClose}
            onMaximize={onOpenPreview}
            tagOptions={tagOptions}
            {...restDetailProps}
          />
        );
        if (folderNodes && ensureFolderData) {
          return (
            <FolderManagerProvider folderNodes={folderNodes} ensureFolderData={ensureFolderData}>
              {viewer}
            </FolderManagerProvider>
          );
        }
        return (
          <>{viewer}</>
        );
      })()
      : null;

    return {
      content: (
        <DocumentsPanel
          {...documentsTableProps}
          headerLeading={sidebarToggle}
        />
      ),
      detail,
      detailMode,
    };
  }, [
    documentsTableProps,
    renderSidebarToggle,
    detailPanelOpen,
    detailPanelProps,
  ]);

  const showPreviewWorkspace = Boolean(previewDocumentId);

  const previewSurface = useMemo<WorkspaceSurface>(() => {
    if (!showPreviewWorkspace) {
      return null;
    }

    const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
    const detailExtras = detailPanelProps || {};
    const {
      tagLookupById,
      tags: tagOptions,
      onTagAdd,
      onTagRemove,
      correspondents,
      onCorrespondentAdd,
      onCorrespondentRemove,
      onUpdateTitle,
      onUpdateIssued,
      resolveFolderPath,
      folderNodes,
      ensureFolderData,
    } = detailExtras;

    const viewer = (
      <DocumentViewerPanel
        document={previewWorkspaceDocument || null}
        hydrateDocument={ensurePreviewData}
        tagLookupById={tagLookupById}
        tagOptions={tagOptions}
        onTagAdd={onTagAdd}
        onTagRemove={onTagRemove}
        correspondents={correspondents}
        onCorrespondentAdd={onCorrespondentAdd}
        onCorrespondentRemove={onCorrespondentRemove}
        onUpdateTitle={onUpdateTitle}
        onUpdateIssued={onUpdateIssued}
        ensureAssetUrl={ensureAssetUrl}
        getDocumentAsset={getDocumentAsset}
        ensurePreviewData={ensurePreviewData}
        notifyApiError={notifyApiError}
        sidebarToggle={sidebarToggle}
        onClose={closeDocumentPreview}
        resolveFolderPath={resolveFolderPath}
      />
    );

    const content = folderNodes && ensureFolderData
      ? (
        <FolderManagerProvider folderNodes={folderNodes} ensureFolderData={ensureFolderData}>
          {viewer}
        </FolderManagerProvider>
      )
      : viewer;

    return { content, detail: null, detailMode: null };
  }, [
    showPreviewWorkspace,
    previewWorkspaceDocument,
    ensurePreviewData,
    ensureAssetUrl,
    getDocumentAsset,
    notifyApiError,
    renderSidebarToggle,
    closeDocumentPreview,
    detailPanelProps,
  ]);

  const surface = useMemo<WorkspaceSurface>(() => {
    if (showPreviewWorkspace) {
      return previewSurface;
    }
    return documentsSurface;
  }, [showPreviewWorkspace, previewSurface, documentsSurface]);

  return { surface };
};
