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/documentSummary';
import { createDocumentActionState } from '../documents/documentActions';
import { resolveDocumentAssetUrl } from '../asset_manager';
import PanelHeader from '../ui/PanelHeader';
import BreadcrumbTrail from '../ui/BreadcrumbTrail';
import DocumentViewerLayout from './DocumentViewerLayout';
import useViewerLayoutMode from './useViewerLayoutMode';
import { usePanelResizeBindings } from '../app/PanelManagerContext';
import type { DocumentId, FolderId } from '../types/identifiers';
import type { Document } from '../types/documents';
import type { AssetLike } from '../types/assets';

type SidebarMode = 'overlay' | 'inline';

interface DocumentViewerPanelProps extends DocumentSummarySectionProps {
  document: Document | null;
  ensureAssetUrl?: (docId: DocumentId, asset: AssetLike, options?: { force?: boolean }) => Promise<unknown>;
  getDocumentAsset?: (doc: Document | null, type: string) => AssetLike | null;
  ensurePreviewData?: (docId: DocumentId, options?: { signal?: AbortSignal }) => Promise<Document | null>;
  notifyApiError?: (error: unknown, fallbackMessage?: string) => void;
  sidebarToggle?: ReactNode;
  onClosePanel?: () => void;
  resolveFolderPath?: (doc: Document | null) => Array<{ id?: string; name?: string }>;
  variant?: 'viewer' | 'sidebar';
  onCollapsePanel?: () => void;
  onMaximizePanel?: (args: { documentIds: Array<string> }) => void;
  sidebarMode?: SidebarMode;
}

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

  const downloadHref = actionState?.downloadHref;
  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,
  tagLookupById,
  tagOptions,
  onTagAdd,
  onTagRemove,
  correspondents,
  onCorrespondentAdd,
  onCorrespondentRemove,
  onUpdateTitle,
  onUpdateIssued,
  ensureAssetUrl,
  getDocumentAsset,
  ensurePreviewData,
  notifyApiError,
  sidebarToggle = null,
  onClosePanel,
  resolveFolderPath,
  variant = 'viewer',
  onCollapsePanel,
  onMaximizePanel,
  sidebarMode = 'overlay',
}) => {
  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 || !getDocumentAsset) {
      return false;
    }
    return Boolean(getDocumentAsset(document, 'ocr-text'));
  }, [document, getDocumentAsset]);

  const navigateToFolder = useCallback(
    (folderId: FolderId | null) => {
      const target = folderId == null
        ? '/documents'
        : `/documents/folder/${folderId}`;
      navigate(target);
    },
    [navigate],
  );

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

  const loadOcrContent = useCallback(async ({ signal }: { signal?: AbortSignal } = {}) => {
    if (!document || !hasOcr || !getDocumentAsset) {
      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 && ensureAssetUrl) {
      await ensureAssetUrl(document.id, asset, { force: true });
      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 resolvedDocumentLink = useMemo(() => {
    if (!document) {
      return null;
    }
    const downloadUrl = document.current_version?.download?.url;
    const href = downloadUrl;
    if (!href) {
      return null;
    }
    const mimeType = document.mime_type;
    const filename = document.current_version?.filename || document.filename || document.title || null;
    return {
      url: href,
      mimeType,
      filename,
    };
  }, [document]);

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

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

  useEffect(() => {
    setZoomOverlayOpen(false);
  }, [resolvedDocumentLink?.url, 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,
          ensurePreviewData,
          ensureAssetUrl,
          getDocumentAsset,
          notifyApiError,
          ocrErrorMessage: 'Unable to open OCR text.',
        })
        : null,
    [
      document,
      ensurePreviewData,
      ensureAssetUrl,
      getDocumentAsset,
      notifyApiError,
    ],
  );

  const breadcrumbs = useMemo(() => {
    if (!document || !resolveFolderPath) {
      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 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 ? () => navigateToFolder(crumb.id) : null,
    }));
  }, [breadcrumbs, navigateToFolder]);

  const zoomDisplay = useMemo(() => {
    if (!resolvedDocumentLink?.url || !document) {
      return null;
    }
    const normalizedMimeType = document.mime_type;
    return {
      url: resolvedDocumentLink.url,
      alt: document.title,
      mimeType: normalizedMimeType,
    };
  }, [document, resolvedDocumentLink?.url]);

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

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

  const maximizeButton = isSidebarVariant && onMaximizePanel
    ? (
      <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 ? <React.Fragment key="collapse-button">{collapseButton}</React.Fragment> : null,
      maximizeButton ? <React.Fragment key="maximize-button">{maximizeButton}</React.Fragment> : null,
    ].filter(Boolean)
    : [
      sidebarToggle ? <React.Fragment key="sidebar-toggle">{sidebarToggle}</React.Fragment> : null,
      closeButton ? <React.Fragment key="close-button">{closeButton}</React.Fragment> : null,
    ].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}
          documentLink={resolvedDocumentLink}
          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 overlayDocument = useMemo(() => (
    document && zoomDisplay?.url
      ? { ...document, documentLink: zoomDisplay }
      : document
  ), [document, zoomDisplay]);

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

  if (isSidebarVariant) {
    const sidebarClass = `detail-panel panel${sidebarMode === 'inline' ? ' detail-panel--inline' : ''}${isPanelResizing ? ' detail-panel--resizing' : ''}`;
    return (
      <>
        <aside
          className={sidebarClass}
          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;
