import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import type { ReactNode } from 'react';
import { useNavigate } from 'react-router-dom';
import {
  DownloadIcon,
  CloseIcon,
  IconZoomInArea,
  IconX,
  WindowMaximizeIcon,
} from '../ui/icons';
import PreviewZoomOverlay from '../detail/PreviewZoomOverlay';
import {
  buildCorrespondentOptions,
  sortCorrespondents,
} from '../documents/DocumentSummarySection';
import type { DocumentSummarySectionProps } from '../documents/DocumentSummarySection';
import { extractDocumentMetadataPayload } from '../documents/documentMetadata';
import { createDocumentActionState } from '../documents/documentActions';
import { resolveDocumentAssetUrl } from '../asset_manager';
import PanelHeader from '../ui/PanelHeader';
import BreadcrumbTrail from '../ui/BreadcrumbTrail';
import { useAssetNavigator } from '../hooks/useAssetNavigator';
import DocumentViewerLayout from './DocumentViewerLayout';
import useViewerLayoutMode from './useViewerLayoutMode';
import { usePanelResizeBindings } from '../app/PanelManagerContext';

interface DocumentLike {
  id?: string | number;
  title?: string;
  issued_at?: string | null;
  correspondents?: Array<{ id?: string | number; name?: string }>;
  [key: string]: unknown;
}

interface AssetLike {
  id?: string | number;
  url?: string | null;
  metadata?: Record<string, unknown> | null;
  [key: string]: unknown;
}

interface DocumentViewerPanelProps extends DocumentSummarySectionProps {
  document: DocumentLike | null;
  previewEntry?: {
    url?: string;
    canGoPrev?: boolean;
    canGoNext?: boolean;
    goPrev?: () => void;
    goNext?: () => void;
  } | null;
  hydrateDocument?: (doc: DocumentLike | null) => DocumentLike | null;
  ensureAssetUrl?: (docId: string | number, asset: AssetLike, options?: { start?: number; limit?: number }) => Promise<unknown>;
  getDocumentAsset?: (doc: DocumentLike | null, type: string) => AssetLike | null | undefined;
  ensurePreviewData?: (docId: string | number, options?: { signal?: AbortSignal }) => Promise<DocumentLike | null | undefined>;
  resolveApiPath?: (path: string) => string;
  notifyApiError?: (error: unknown, fallbackMessage?: string) => void;
  sidebarToggle?: ReactNode;
  onClosePanel?: () => void;
  resolveFolderPath?: (doc: DocumentLike | null) => Array<{ id?: string | number; name?: string }>;
  variant?: 'viewer' | 'sidebar';
  onCollapsePanel?: () => void;
  onMaximizePanel?: (args: { documentIds: Array<string | number> }) => void;
}


export const createDocumentViewerHeaderActions = ({
  document,
  actionState,
  previewEntry,
  onZoom,
  canZoom = false,
}) => {
  if (!document) {
    return null;
  }

  const downloadHref = actionState?.downloadHref || previewEntry?.url;
  if (!downloadHref && !(canZoom && onZoom)) {
    return null;
  }

  return (
    <>
      {downloadHref ? (
        <a
          className="icon-button"
          href={downloadHref}
          target="_blank"
          rel="noopener noreferrer"
          aria-label="Download document"
          title="Download document"
        >
          <DownloadIcon />
        </a>
      ) : null}
      {canZoom && onZoom ? (
        <button
          type="button"
          className="icon-button"
          onClick={onZoom}
          aria-label="Open zoom preview"
          title="Open zoom preview"
        >
          <IconZoomInArea />
        </button>
      ) : null}
    </>
  );
};

const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
  document,
  previewEntry,
  hydrateDocument,
  tagLookupById,
  tagOptions,
  onTagAdd,
  onTagRemove,
  correspondents,
  onCorrespondentAdd,
  onCorrespondentRemove,
  onUpdateTitle,
  onUpdateIssued,
  ensureAssetUrl,
  getDocumentAsset,
  ensurePreviewData,
  resolveApiPath,
  notifyApiError,
  sidebarToggle = null,
  onClosePanel,
  resolveFolderPath,
  variant = 'viewer',
  onCollapsePanel,
  onMaximizePanel,
}) => {
  const navigate = useNavigate();
  const isSidebarVariant = variant === 'sidebar';
  const sortedCorrespondents = useMemo(
    () => sortCorrespondents(document?.correspondents || []),
    [document],
  );

  const correspondentOptions = useMemo(
    () => buildCorrespondentOptions(Array.isArray(correspondents) ? correspondents : []),
    [correspondents],
  );

  const metadataPayload = useMemo(
    () => extractDocumentMetadataPayload(document),
    [document],
  );

  const hasOcr = useMemo(() => {
    if (!document || typeof getDocumentAsset !== 'function') {
      return false;
    }
    return Boolean(getDocumentAsset(document, 'ocr-text'));
  }, [document, getDocumentAsset]);

  const summaryProps = useMemo(
    () => ({
      tagLookupById,
      tagOptions,
      onTagAdd,
      onTagRemove,
      correspondents: sortedCorrespondents,
      correspondentOptions,
      onCorrespondentAdd,
      onCorrespondentRemove,
      onUpdateTitle,
      onUpdateIssued,
    }),
    [
      tagLookupById,
      tagOptions,
      onTagAdd,
      onTagRemove,
      sortedCorrespondents,
      correspondentOptions,
      onCorrespondentAdd,
      onCorrespondentRemove,
      onUpdateTitle,
      onUpdateIssued,
    ],
  );

  const loadOcrContent = useCallback(async ({ signal }: { signal?: AbortSignal } = {}) => {
    if (!document || !hasOcr || typeof getDocumentAsset !== 'function') {
      return '';
    }

    const updateUrl = () =>
      resolveDocumentAssetUrl(document, 'ocr-text', {
        ensureAssetUrl,
        getAsset: getDocumentAsset,
      });

    const asset = getDocumentAsset(document, 'ocr-text');
    let url = updateUrl();

    if (!url && document.id && asset?.id && typeof ensureAssetUrl === 'function') {
      await ensureAssetUrl(document.id, asset, { start: 1, limit: 1 });
      if (signal?.aborted) {
        throw new DOMException('Aborted', 'AbortError');
      }
      url = updateUrl();
    }

    if (!url) {
      return '';
    }

    const response = await fetch(url, {
      method: 'GET',
      mode: 'cors',
      credentials: 'omit',
      signal,
    });

    if (!response.ok) {
      throw new Error(`Unexpected status: ${response.status}`);
    }

    return response.text();
  }, [document, hasOcr, getDocumentAsset, ensureAssetUrl]);

  const contentTabConfig = useMemo(
    () => ({
      enabled: hasOcr,
      id: 'content',
      label: 'Content',
      loadContent: loadOcrContent,
      loadingMessage: 'Loading OCR content…',
      emptyMessage: 'No OCR content available.',
      unavailableMessage: 'No OCR content available.',
      errorMessage: 'Failed to load OCR content.',
    }),
    [hasOcr, loadOcrContent],
  );

  const [zoomOverlayOpen, setZoomOverlayOpen] = useState(false);
  const previewNavigator = useAssetNavigator({
    document,
    assetType: 'preview',
    ensureAssetUrl,
    getAsset: getDocumentAsset,
    prefetch: 3,
  });
  const navigatorUrl = previewNavigator?.currentUrl;
  const navigatorCanGoPrev = Boolean(previewNavigator?.canGoPrev);
  const navigatorCanGoNext = Boolean(previewNavigator?.canGoNext);
  const navigatorGoPrev = previewNavigator?.goPrev;
  const navigatorGoNext = previewNavigator?.goNext;

  const handleZoomOpen = useCallback(() => {
    if (!previewEntry?.url) {
      return;
    }
    setZoomOverlayOpen(true);
  }, [previewEntry?.url]);

  const handleZoomClose = useCallback(() => {
    setZoomOverlayOpen(false);
  }, []);

  useEffect(() => {
    setZoomOverlayOpen(false);
  }, [previewEntry?.url, document?.id]);

  useEffect(() => {
    if (typeof hydrateDocument === 'function' && document?.id) {
      hydrateDocument(document.id);
    }
  }, [hydrateDocument, document?.id]);

const panelRef = useRef<HTMLDivElement | HTMLFormElement | HTMLElement | null>(null);
  const isStackedLayout = useViewerLayoutMode(panelRef, document?.id);

  const {
    panelStyle: managedDetailPanelStyle,
    handleProps: managedResizeHandleProps,
    isPanelResizing,
  } = usePanelResizeBindings('detail', { enabled: isSidebarVariant, panelRef });
  const detailPanelStyle = isSidebarVariant ? managedDetailPanelStyle : undefined;
  const resizeHandleProps = isSidebarVariant ? managedResizeHandleProps : {};

  const viewerClassName = isStackedLayout
    ? 'document-viewer document-viewer--stacked'
    : 'document-viewer';

  const actionState = useMemo(
    () =>
      document
        ? createDocumentActionState({
            document,
            resolveApiPath,
            ensurePreviewData,
            ensureAssetUrl,
            getDocumentAsset,
            notifyApiError,
            ocrErrorMessage: 'Unable to open OCR text.',
          })
        : null,
    [
      document,
      resolveApiPath,
      ensurePreviewData,
      ensureAssetUrl,
      getDocumentAsset,
      notifyApiError,
    ],
  );

  const breadcrumbs = useMemo(() => {
    if (!document || typeof resolveFolderPath !== 'function') {
      return [];
    }
    const folderSegments = resolveFolderPath(document.folder_id);
    const normalizedSegments = Array.isArray(folderSegments)
      ? folderSegments
          .filter((segment) => segment && segment.id && segment.name)
          .map((segment) => ({ id: segment.id, name: segment.name }))
      : [];

    return [
      ...normalizedSegments,
      { id: document.id, name: document.title },
    ];
  }, [document, resolveFolderPath]);

  const handleBreadcrumbNavigate = useCallback(
    (crumb) => {
      if (!crumb?.id) {
        return;
      }
      const target = crumb.id === 'root'
        ? '/documents'
        : `/documents/folder/${crumb.id}`;
      navigate(target);
    },
    [navigate],
  );

  const breadcrumbTrailEntries = useMemo(() => {
    if (!breadcrumbs.length) {
      return [];
    }
    const lastIndex = breadcrumbs.length - 1;
    return breadcrumbs.map((crumb, index) => ({
      id: crumb.id,
      label: crumb.name,
      onClick: index < lastIndex ? () => handleBreadcrumbNavigate(crumb) : null,
    }));
  }, [breadcrumbs, handleBreadcrumbNavigate]);

  const zoomDisplay = useMemo(() => {
    if (navigatorUrl && document) {
      return {
        url: navigatorUrl,
        alt: document.title,
        canGoPrev: navigatorCanGoPrev,
        canGoNext: navigatorCanGoNext,
        goPrev: navigatorCanGoPrev ? navigatorGoPrev : undefined,
        goNext: navigatorCanGoNext ? navigatorGoNext : undefined,
      };
    }
    if (previewEntry?.url && document) {
      return {
        url: previewEntry.url,
        alt: document.title,
        canGoPrev: false,
        canGoNext: false,
      };
    }
    return null;
  }, [
    navigatorUrl,
    navigatorCanGoPrev,
    navigatorCanGoNext,
    navigatorGoPrev,
    navigatorGoNext,
    previewEntry?.url,
    document,
  ]);

  const headerActions = createDocumentViewerHeaderActions({
    document,
    actionState,
    previewEntry,
    onZoom: zoomDisplay ? handleZoomOpen : null,
    canZoom: Boolean(zoomDisplay),
  });

  const collapseButton = isSidebarVariant && typeof onCollapsePanel === 'function'
    ? (
        <button
          type="button"
          className="icon-button"
          onClick={() => onCollapsePanel?.()}
          aria-label="Close detail panel"
          title="Close detail panel"
        >
          <IconX />
        </button>
      )
    : null;

  const maximizeButton = isSidebarVariant && typeof onMaximizePanel === 'function'
    ? (
        <button
          type="button"
          className="icon-button"
          onClick={(event) => {
            event.stopPropagation();
            const targetId = document?.id;
            if (targetId == null) {
              return;
            }
            onMaximizePanel?.({ documentIds: [targetId] });
          }}
          aria-label="Maximize"
          title="Maximize"
        >
          <WindowMaximizeIcon className="icon--flip-y" />
        </button>
      )
    : null;

  const closeButton = !isSidebarVariant && onClosePanel
    ? (
        <button
          type="button"
          className="icon-button"
          onClick={() => onClosePanel?.()}
          aria-label="Close preview"
          title="Close preview"
        >
          <CloseIcon />
        </button>
      )
    : null;

  const headerLeadingButtons = isSidebarVariant
    ? [collapseButton, maximizeButton].filter(Boolean)
    : [sidebarToggle, closeButton].filter(Boolean);
  const headerLeadingContent = headerLeadingButtons.length
    ? (
        <>
          {headerLeadingButtons}
        </>
      )
    : null;

  const resizeHandle = isSidebarVariant ? (
    <button
      type="button"
      className={`detail-panel__resize-handle${isPanelResizing ? ' is-active' : ''}`}
      aria-label="Resize detail panel"
      {...resizeHandleProps}
    >
      <span aria-hidden="true" />
    </button>
  ) : null;

  const loadingSection = (
    <div className="document-viewer-panel__body">
      <section className="document-viewer document-viewer--loading">
        <div className="document-viewer__details-pane">
          <div className="document-viewer__details">
            <div className="document-viewer__message">Loading document…</div>
          </div>
        </div>
        <div className="document-viewer__viewport">
          <div className="document-viewer__message">Preparing preview…</div>
        </div>
      </section>
    </div>
  );

  const viewerSection = document ? (
    <div
      className={isStackedLayout
        ? 'document-viewer-panel__body document-viewer-panel__body--stacked'
        : 'document-viewer-panel__body'}
    >
      <section className={viewerClassName}>
        <DocumentViewerLayout
          document={document}
          previewEntry={previewEntry}
          summaryProps={summaryProps}
          metadataPayload={metadataPayload}
          contentTabConfig={contentTabConfig}
          previewLoadingMessage="Loading preview…"
          layoutMode={isStackedLayout ? 'stacked' : 'split'}
        />
      </section>
    </div>
  ) : loadingSection;

  const headerTitle = breadcrumbTrailEntries.length ? (
    <BreadcrumbTrail
      entries={breadcrumbTrailEntries}
      separator="/"
      className="panel-header__breadcrumbs"
      truncateFromStart={isSidebarVariant}
    />
  ) : (
    document?.title || 'Document preview'
  );

  const overlay = (
    <PreviewZoomOverlay
      open={Boolean(zoomOverlayOpen && zoomDisplay)}
      display={zoomDisplay}
      onClose={handleZoomClose}
    />
  );

  if (isSidebarVariant) {
    return (
      <>
        <aside
          className={`detail-panel panel${isPanelResizing ? ' detail-panel--resizing' : ''}`}
          ref={panelRef}
          style={detailPanelStyle}
        >
          {resizeHandle}
          <PanelHeader
            leading={headerLeadingContent}
            title={headerTitle}
            titleTag="h3"
            actions={headerActions}
          />
          <div className="panel-body detail-panel__content">{viewerSection}</div>
        </aside>
        {overlay}
      </>
    );
  }

  return (
    <>
      <section className="document-viewer-panel" ref={panelRef}>
        <PanelHeader
          leading={headerLeadingContent}
          title={headerTitle}
          titleTag="h3"
          actions={headerActions}
        />
        {viewerSection}
      </section>
      {overlay}
    </>
  );
};

export default DocumentViewerPanel;

export const createDocumentViewerSurface = ({
  document,
  previewEntry,
  ensureAssetUrl,
  ensurePreviewData,
  getDocumentAsset,
  resolveApiPath,
  notifyApiError,
  onClose,
  renderSidebarToggle,
  tagLookupById,
  tagOptions,
  onTagAdd,
  onTagRemove,
  correspondents,
  onCorrespondentAdd,
  onCorrespondentRemove,
  onUpdateTitle,
  onUpdateIssued,
  resolveFolderPath,
}) => {
  if (!document) {
    return null;
  }

  const sidebarToggle = typeof renderSidebarToggle === 'function'
    ? renderSidebarToggle()
    : null;

  return {
    key: 'preview',
    variant: 'preview',
    header: null,
    content: (
      <DocumentViewerPanel
        document={document}
        previewEntry={previewEntry}
        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}
        resolveApiPath={resolveApiPath}
        notifyApiError={notifyApiError}
        sidebarToggle={sidebarToggle}
        onClosePanel={onClose}
        resolveFolderPath={resolveFolderPath}
      />
    ),
    supportsDetail: false,
  };
};
