import { Button } from '@learnitive/ui-components';
import { ChevronLeft, ChevronRight, ExternalLink, Maximize2, ZoomIn, ZoomOut } from 'lucide-react';
import * as pdfjs from 'pdfjs-dist';
import React from 'react';

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/build/pdf.worker.min.mjs',
  import.meta.url,
).toString();

const MIN_ZOOM = 0.5;
const MAX_ZOOM = 2.5;
const ZOOM_STEP = 0.15;

type Props = {
  url: string;
  title: string;
  compact?: boolean;
};

function clamp(value: number, min: number, max: number) {
  return Math.min(max, Math.max(min, value));
}

export function TemplatePdfPreview({ url, title, compact = false }: Props) {
  const canvasRef = React.useRef<HTMLCanvasElement>(null);
  const frameRef = React.useRef<HTMLDivElement>(null);
  const [documentProxy, setDocumentProxy] = React.useState<pdfjs.PDFDocumentProxy | null>(null);
  const [page, setPage] = React.useState(1);
  const [zoom, setZoom] = React.useState(1);
  const [fitWidth, setFitWidth] = React.useState(true);
  const [frameWidth, setFrameWidth] = React.useState(0);
  const [loading, setLoading] = React.useState(true);
  const [rendering, setRendering] = React.useState(false);
  const [error, setError] = React.useState('');

  React.useEffect(() => {
    const element = frameRef.current;
    if (!element) return;
    const update = () => setFrameWidth(Math.max(0, element.clientWidth));
    update();
    const observer = new ResizeObserver(update);
    observer.observe(element);
    return () => observer.disconnect();
  }, []);

  React.useEffect(() => {
    let cancelled = false;
    const task = pdfjs.getDocument({ url, withCredentials: true });
    setLoading(true);
    setError('');
    setDocumentProxy(null);
    setPage(1);
    void task.promise.then((nextDocument) => {
      if (cancelled) return;
      setDocumentProxy(nextDocument);
    }).catch((reason) => {
      if (!cancelled) setError(reason instanceof Error ? reason.message : 'Unable to load this PDF preview.');
    }).finally(() => {
      if (!cancelled) setLoading(false);
    });
    return () => {
      cancelled = true;
      void task.destroy();
    };
  }, [url]);

  React.useEffect(() => {
    if (!documentProxy || !canvasRef.current) return;
    let cancelled = false;
    let renderTask: pdfjs.RenderTask | undefined;
    setRendering(true);
    setError('');
    void documentProxy.getPage(page).then((pdfPage) => {
      if (cancelled || !canvasRef.current) return;
      const baseViewport = pdfPage.getViewport({ scale: 1 });
      const available = Math.max(240, frameWidth - (compact ? 16 : 32));
      const fitted = available / baseViewport.width;
      const scale = clamp((fitWidth ? fitted : 1) * zoom, MIN_ZOOM, MAX_ZOOM * Math.max(1, fitted));
      const viewport = pdfPage.getViewport({ scale });
      const pixelRatio = Math.min(window.devicePixelRatio || 1, 2);
      const canvas = canvasRef.current;
      const context = canvas.getContext('2d', { alpha: false });
      if (!context) throw new Error('PDF canvas is unavailable.');
      canvas.width = Math.max(1, Math.floor(viewport.width * pixelRatio));
      canvas.height = Math.max(1, Math.floor(viewport.height * pixelRatio));
      canvas.style.width = `${Math.floor(viewport.width)}px`;
      canvas.style.height = `${Math.floor(viewport.height)}px`;
      renderTask = pdfPage.render({
        canvas,
        canvasContext: context,
        viewport,
        transform: pixelRatio === 1 ? undefined : [pixelRatio, 0, 0, pixelRatio, 0, 0],
      });
      return renderTask.promise;
    }).catch((reason) => {
      if (!cancelled && !(reason instanceof Error && /cancel/i.test(reason.message))) {
        setError(reason instanceof Error ? reason.message : 'Unable to render this PDF preview.');
      }
    }).finally(() => {
      if (!cancelled) setRendering(false);
    });
    return () => {
      cancelled = true;
      renderTask?.cancel();
    };
  }, [compact, documentProxy, fitWidth, frameWidth, page, zoom]);

  const total = documentProxy?.numPages || 0;
  const percent = Math.round(zoom * 100);
  return <div className={`interactive-template-pdfjs${compact ? ' is-compact' : ''}`}>
    {!compact ? <div className="interactive-template-pdfjs-toolbar" role="toolbar" aria-label="PDF preview controls">
      <div className="interactive-template-pdfjs-page-controls">
        <Button size="sm" variant="outline" disabled={!documentProxy || page <= 1} onClick={() => setPage((value) => Math.max(1, value - 1))} aria-label="Previous PDF page"><ChevronLeft className="size-4"/></Button>
        <span>Page {page} / {total || '—'}</span>
        <Button size="sm" variant="outline" disabled={!documentProxy || page >= total} onClick={() => setPage((value) => Math.min(total, value + 1))} aria-label="Next PDF page"><ChevronRight className="size-4"/></Button>
      </div>
      <div className="interactive-template-pdfjs-zoom-controls">
        <Button size="sm" variant="outline" disabled={zoom <= MIN_ZOOM} onClick={() => { setFitWidth(false); setZoom((value) => clamp(value - ZOOM_STEP, MIN_ZOOM, MAX_ZOOM)); }} aria-label="Zoom out"><ZoomOut className="size-4"/></Button>
        <span>{percent}%</span>
        <Button size="sm" variant="outline" disabled={zoom >= MAX_ZOOM} onClick={() => { setFitWidth(false); setZoom((value) => clamp(value + ZOOM_STEP, MIN_ZOOM, MAX_ZOOM)); }} aria-label="Zoom in"><ZoomIn className="size-4"/></Button>
        <Button size="sm" variant={fitWidth ? 'default' : 'outline'} onClick={() => { setFitWidth(true); setZoom(1); }}><Maximize2 className="size-4"/> Fit width</Button>
        <a className="interactive-button interactive-button-secondary interactive-button-sm" href={url} target="_blank" rel="noreferrer"><ExternalLink className="size-4"/> Open PDF</a>
      </div>
    </div> : null}
    <div className="interactive-template-pdfjs-frame" ref={frameRef} aria-busy={loading || rendering}>
      {loading ? <div className="interactive-template-pdfjs-state">Loading PDF preview…</div> : null}
      {error ? <div className="interactive-template-pdfjs-state is-error"><strong>PDF preview unavailable.</strong><span>{error}</span><a className="interactive-text-link" href={url} target="_blank" rel="noreferrer">Open PDF</a></div> : null}
      {!error ? <canvas ref={canvasRef} aria-label={`${title} PDF preview, page ${page}`}/> : null}
    </div>
  </div>;
}
