import { useCallback, useMemo, useRef } from 'react';
import type { JSX } from 'react';
import DocumentInfoPanel from '../documents/DocumentInfoPanel';
import { DownloadIcon } from '../ui/icons';
import PdfViewer from './PdfViewer';
import { AUDIO_EXTENSIONS, VIDEO_EXTENSIONS } from '../constants/preview';

import type { Document } from '../types/documents';

interface DocumentLink {
  url?: string;
  mimeType?: string;
  filename?: string;
}

interface ContentTabConfig {
  id?: string;
  label?: string;
  enabled?: boolean;
  forceDisplay?: boolean;
  loadContent?: (options?: { signal?: AbortSignal }) => unknown | Promise<unknown>;
  loadingMessage?: string;
  emptyMessage?: string;
  unavailableMessage?: string;
  errorMessage?: string;
  [key: string]: unknown;
}

type LayoutMode = 'split' | 'stacked' | (string & {});

interface DocumentViewerLayoutProps {
  document?: Document | null;
  documentLink?: DocumentLink | null;
  summaryProps?: Record<string, unknown>;
  metadataPayload?: unknown;
  contentTabConfig?: ContentTabConfig | null;
  resetKey?: string | null;
  classNamePrefix?: string;
  defaultTabId?: string;
  infoPanelProps?: Record<string, unknown>;
  previewLoadingMessage?: string;
  layoutMode?: LayoutMode;
}

const getFileExtension = (filename?: string | null) => {
  if (!filename) {
    return '';
  }
  const match = filename.toLowerCase().match(/\.([a-z0-9]+)$/);
  return match ? match[1] : '';
};

const DocumentViewerLayout = ({
  document,
  documentLink,
  summaryProps = {},
  metadataPayload,
  contentTabConfig,
  resetKey,
  classNamePrefix = 'document-viewer',
  defaultTabId = 'details',
  infoPanelProps = {},
  previewLoadingMessage = 'Preparing preview…',
  layoutMode = 'split',
}: DocumentViewerLayoutProps): JSX.Element => {
  const isStacked = layoutMode === 'stacked';
  const viewportRef = useRef<HTMLDivElement>(null);

  const previewContent = useMemo(() => {
    if (!document || !documentLink?.url) {
      return null;
    }

    const normalizedMimeType = (documentLink.mimeType
      || document.mime_type
      || '')
      .toLowerCase();
    const normalizedFilename = documentLink.filename
      || document.filename
      || document.original_name
      || '';
    const fileExtension = getFileExtension(normalizedFilename);
    const isImage = normalizedMimeType.startsWith('image/');
    const isPdf = normalizedMimeType === 'application/pdf'
      || normalizedMimeType === 'application/x-pdf';
    const isAudio = normalizedMimeType.startsWith('audio/')
      || AUDIO_EXTENSIONS.has(fileExtension);
    const isVideo = normalizedMimeType.startsWith('video/')
      || VIDEO_EXTENSIONS.has(fileExtension);
    const mediaLabel = document.title
      || normalizedFilename
      || 'Document preview';

    if (isImage) {
      return (
        <img
          src={documentLink.url}
          alt={`Preview of ${document.title}`}
          className="document-viewer__object document-viewer__object--image"
          draggable={false}
        />
      );
    }

    if (isPdf) {
      const documentTitle = document.title
        || document.filename
        || document.original_name;
      return (
        <PdfViewer
          src={documentLink.url}
          title={documentTitle ? `Preview of ${documentTitle}` : undefined}
          viewportRef={viewportRef}
        />
      );
    }

    if (isAudio) {
      return (
        <audio
          className="document-viewer__object document-viewer__object--audio"
          controls
          preload="metadata"
          src={documentLink.url}
          aria-label={`Audio preview of ${mediaLabel}`}
        >
        </audio>
      );
    }

    if (isVideo) {
      return (
        <video
          className="document-viewer__object document-viewer__object--video"
          controls
          preload="metadata"
          src={documentLink.url}
          aria-label={`Video preview of ${mediaLabel}`}
        >
        </video>
      );
    }

    const displayMimeType = document.mime_type || documentLink.mimeType || 'this file type';
    const displayFilename = documentLink.filename
      || document.filename
      || document.original_name
      || 'download';

    return (
      <div className="document-viewer__unsupported">
        <div className="document-viewer__unsupported-message">
          Preview is not available for {displayMimeType} files.
        </div>
        <div className="document-viewer__unsupported-filename">{displayFilename}</div>
        <a
          className="button-link document-viewer__unsupported-download"
          href={documentLink.url}
          download={displayFilename}
          target="_blank"
          rel="noopener noreferrer"
        >
          <DownloadIcon />
          <span>Download</span>
        </a>
      </div>
    );
  }, [document, documentLink, viewportRef]);

  const renderViewportPane = useCallback(() => (
    <div className="document-viewer__viewport" ref={viewportRef}>
      {!documentLink?.url ? (
        <div className="document-viewer__message">{previewLoadingMessage}</div>
      ) : (
        previewContent
      )}
    </div>
  ), [previewContent, documentLink?.url, previewLoadingMessage, viewportRef]);

  const viewportPane = renderViewportPane();

  const stackedLeadingTabs = useMemo(() => (
    isStacked
      ? [
        {
          id: 'preview',
          label: 'Preview',
          render: () => renderViewportPane(),
        },
      ]
      : []
  ), [isStacked, renderViewportPane]);

  const resolvedDefaultTabId = isStacked ? 'preview' : defaultTabId;
  const summaryPlacement = 'tabs';
  const tabsPlacement = 'bottom';
  const summaryLayout = 'compact';

  const detailsPane = (
    <div className="document-viewer__details-pane">
      <div className="document-viewer__details">
        <DocumentInfoPanel
          document={document}
          summaryProps={summaryProps}
          metadataPayload={metadataPayload}
          contentConfig={contentTabConfig}
          defaultTabId={resolvedDefaultTabId}
          classNamePrefix={classNamePrefix}
          hideTabNavWhenSingle={false}
          resetKey={resetKey || document?.id}
          summaryPlacement={summaryPlacement}
          summaryLayout={summaryLayout}
          leadingTabs={stackedLeadingTabs}
          tabsPlacement={tabsPlacement}
          {...infoPanelProps}
        />
      </div>
    </div>
  );

  if (isStacked) {
    return detailsPane;
  }

  return (
    <>
      {detailsPane}
      {viewportPane}
    </>
  );
};

export default DocumentViewerLayout;
