"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { Loader2, ChevronLeft, ChevronRight, Eraser, Check, Download } from "lucide-react";
import { renderPdfPage, loadPdfLib, downloadBlob, loadImageBitmapEl, fmtBytes } from "@/lib/files";
import { useApp } from "@/components/app-context";
import { t, L } from "@/lib/i18n";
import { hexToRgb } from "@/components/tools/pdf-editor";

const TL = (x: keyof typeof t, lang: "en" | "bn") => (t[x] as { en: string; bn: string })[lang];

/* =============== SIGN PDF =============== */
export function SignPad({ file }: { file: File }) {
  const { lang } = useApp();
  const [pageCount, setPageCount] = useState(0);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(true);
  const [placing, setPlacing] = useState(false);
  const [placed, setPlaced] = useState<{ x: number; y: number } | null>(null);
  const [widthPct, setWidthPct] = useState(25);
  const [saving, setSaving] = useState(false);
  const canvasHostRef = useRef<HTMLDivElement>(null);
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const padRef = useRef<HTMLCanvasElement>(null);
  const dataRef = useRef<ArrayBuffer | null>(null);
  const drawing = useRef(false);
  const [hasInk, setHasInk] = useState(false);

  useEffect(() => {
    (async () => {
      dataRef.current = await file.arrayBuffer();
      const pdfjs = await import("pdfjs-dist");
      pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.mjs";
      const doc = await pdfjs.getDocument({ data: dataRef.current.slice(0) }).promise;
      setPageCount(doc.numPages);
      setLoading(false);
    })();
  }, [file]);

  const renderPage = useCallback(async () => {
    if (!dataRef.current || !canvasHostRef.current) return;
    setLoading(true);
    const host = canvasHostRef.current;
    const wrap = host?.parentElement;
    const { canvas } = await renderPdfPage(dataRef.current, page, Math.min(760, Math.max(320, (wrap?.clientWidth ?? 700) - 32)));
    canvas.style.maxWidth = "100%";
    canvas.className = "rounded-lg shadow-sm";
    host.replaceChildren(canvas);
    canvasRef.current = canvas;
    setLoading(false);
  }, [page]);

  useEffect(() => { if (pageCount) renderPage(); }, [renderPage, pageCount]);

  // signature pad drawing
  const pos = (e: React.MouseEvent | MouseEvent | TouchEvent, pad: HTMLCanvasElement) => {
    const r = pad.getBoundingClientRect();
    const src = "touches" in e ? e.touches[0] : (e as MouseEvent);
    return { x: ((src.clientX - r.left) / r.width) * pad.width, y: ((src.clientY - r.top) / r.height) * pad.height };
  };

  const startDraw = (e: React.MouseEvent) => {
    const pad = padRef.current;
    if (!pad) return;
    drawing.current = true;
    const ctx = pad.getContext("2d")!;
    const p = pos(e, pad);
    ctx.beginPath();
    ctx.moveTo(p.x, p.y);
    ctx.lineWidth = 3;
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
    ctx.strokeStyle = "#0f172a";
    setHasInk(true);
  };
  const moveDraw = (e: React.MouseEvent) => {
    if (!drawing.current) return;
    const pad = padRef.current;
    if (!pad) return;
    const ctx = pad.getContext("2d")!;
    const p = pos(e, pad);
    ctx.lineTo(p.x, p.y);
    ctx.stroke();
  };
  const endDraw = () => { drawing.current = false; };

  const clearPad = () => {
    const pad = padRef.current;
    if (!pad) return;
    pad.getContext("2d")!.clearRect(0, 0, pad.width, pad.height);
    setHasInk(false);
  };

  const save = async () => {
    const pad = padRef.current;
    const overlay = canvasRef.current;
    if (!pad || !overlay || !dataRef.current || !placed) return;
    setSaving(true);
    try {
      // trim signature canvas
      const sigCtx = pad.getContext("2d")!;
      const imageData = sigCtx.getImageData(0, 0, pad.width, pad.height);
      let minX = pad.width, minY = pad.height, maxX = 0, maxY = 0;
      for (let y = 0; y < pad.height; y++) {
        for (let x = 0; x < pad.width; x++) {
          if (imageData.data[(y * pad.width + x) * 4 + 3] > 0) {
            if (x < minX) minX = x;
            if (x > maxX) maxX = x;
            if (y < minY) minY = y;
            if (y > maxY) maxY = y;
          }
        }
      }
      if (maxX <= minX) { setSaving(false); return; }
      const tw = maxX - minX + 8;
      const th = maxY - minY + 8;
      const tc = document.createElement("canvas");
      tc.width = tw;
      tc.height = th;
      tc.getContext("2d")!.drawImage(pad, minX - 4, minY - 4, tw, th, 0, 0, tw, th);

      const pdfLib = await loadPdfLib();
      const doc = await pdfLib.PDFDocument.load(dataRef.current.slice(0), { ignoreEncryption: true });
      const png = await tc.toDataURL("image/png");
      const img = await doc.embedPng(png);
      const p = doc.getPage(Math.min(doc.getPageCount(), page) - 1);
      const { width, height } = p.getSize();
      const w = (widthPct / 100) * width;
      const h = (w / tw) * th;
      p.drawImage(img, {
        x: placed.x * width,
        y: height - placed.y * height - h / 2,
        width: w,
        height: h,
      });
      const bytes = await doc.save();
      downloadBlob(new Blob([bytes as BlobPart], { type: "application/pdf" }), file.name.replace(/\.pdf$/i, "") + "-signed.pdf");
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="flex h-full min-h-0 flex-col lg:flex-row">
      <div className="shrink-0 space-y-3 border-b border-zinc-200 bg-zinc-50/70 p-4 dark:border-white/10 dark:bg-white/5 lg:w-72 lg:border-b-0 lg:border-r">
        <p className="text-[13px] font-semibold leading-5 text-zinc-600 dark:text-zinc-300">{TL("signDraw", lang)}</p>
        <div className="rounded-xl border-2 border-dashed border-zinc-300 bg-white dark:border-white/20 dark:bg-white">
          <canvas
            ref={padRef}
            width={560}
            height={200}
            className="w-full cursor-crosshair touch-none rounded-lg"
            onMouseDown={startDraw}
            onMouseMove={moveDraw}
            onMouseUp={endDraw}
            onMouseLeave={endDraw}
          />
        </div>
        <div className="flex items-center gap-2">
          <button onClick={clearPad} className="flex items-center gap-1.5 rounded-lg bg-white px-3 py-2 text-[13px] font-bold text-zinc-700 ring-1 ring-zinc-200 hover:bg-zinc-50 dark:bg-white/5 dark:text-zinc-200 dark:ring-white/10">
            <Eraser className="h-4 w-4" /> {TL("signClear", lang)}
          </button>
          <label className="flex items-center gap-2 text-[12.5px] font-semibold text-zinc-600 dark:text-zinc-300">
            {lang === "bn" ? "সাইজ" : "Size"}: {widthPct}%
            <input type="range" min={8} max={60} value={widthPct} onChange={(e) => setWidthPct(Number(e.target.value))} className="w-28 accent-emerald-700" />
          </label>
        </div>
        <button
          onClick={save}
          disabled={!hasInk || !placed || saving}
          className="flex w-full items-center justify-center gap-2 rounded-lg bg-[#0b7a43] px-3 py-2.5 text-[13.5px] font-bold text-white shadow-sm transition-colors hover:bg-[#096c3b] disabled:opacity-40"
        >
          {saving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Check className="h-4 w-4" />}
          {TL("signPlace", lang)}
        </button>
        <p className="text-[12px] text-zinc-400">
          {placed ? (lang === "bn" ? "সই বসানো হয়েছে ✓" : "Signature placed ✓") : (lang === "bn" ? "পেজে ক্লিক করে বসান" : "Click on the page to place")}
        </p>
      </div>
      <div className="flex min-h-0 flex-1 flex-col bg-zinc-100 dark:bg-black/30">
        <div className="flex items-center justify-center gap-3 border-b border-zinc-200 bg-white/60 px-4 py-2 text-[13px] font-semibold text-zinc-600 dark:border-white/10 dark:text-zinc-300">
          <button onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page <= 1} className="rounded-md p-1 hover:bg-zinc-100 disabled:opacity-30" aria-label="prev"><ChevronLeft className="h-4 w-4" /></button>
          {L("page", lang)} {page} {L("of", lang)} {pageCount}
          <button onClick={() => setPage((p) => Math.min(pageCount, p + 1))} disabled={page >= pageCount} className="rounded-md p-1 hover:bg-zinc-100 disabled:opacity-30" aria-label="next"><ChevronRight className="h-4 w-4" /></button>
        </div>
        <div className="min-h-0 flex-1 overflow-auto p-4">
          <div
            className={`relative mx-auto w-fit ${placing ? "cursor-copy" : ""}`}
            onClick={(e) => {
              if (!canvasRef.current) return;
              const r = canvasRef.current.getBoundingClientRect();
              setPlaced({ x: (e.clientX - r.left) / r.width, y: (e.clientY - r.top) / r.height });
            }}
          >
            <div ref={canvasHostRef} />
            {loading && <div className="flex h-72 w-[560px] max-w-[80vw] items-center justify-center rounded-lg bg-white"><Loader2 className="h-7 w-7 animate-spin text-emerald-600" /></div>}
            {hasInk && placed && canvasRef.current && (
              <img
                src={padRef.current ? (padRef.current.toDataURL()) : ""}
                alt="signature preview"
                className="pointer-events-none absolute -translate-y-1/2"
                style={{ left: `${placed.x * 100}%`, top: `${placed.y * 100}%`, width: `${widthPct}%` }}
              />
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

/* =============== VIEW PDF =============== */
export function PdfViewer({ file }: { file: File }) {
  const { lang } = useApp();
  const [pageCount, setPageCount] = useState(0);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(true);
  const hostRef = useRef<HTMLDivElement>(null);
  const dataRef = useRef<ArrayBuffer | null>(null);

  useEffect(() => {
    (async () => {
      dataRef.current = await file.arrayBuffer();
      const pdfjs = await import("pdfjs-dist");
      pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.mjs";
      const doc = await pdfjs.getDocument({ data: dataRef.current.slice(0) }).promise;
      setPageCount(doc.numPages);
      setLoading(false);
    })();
  }, [file]);

  useEffect(() => {
    if (!dataRef.current || !hostRef.current || !pageCount) return;
    let cancelled = false;
    (async () => {
      setLoading(true);
      const host = hostRef.current!;
      const wrap = host.parentElement;
      const { canvas } = await renderPdfPage(dataRef.current!, page, Math.min(780, Math.max(320, (wrap?.clientWidth ?? 700) - 32)));
      if (cancelled) return;
      canvas.style.maxWidth = "100%";
      canvas.className = "rounded-lg shadow-sm bg-white";
      host.replaceChildren(canvas);
      setLoading(false);
    })();
    return () => { cancelled = true; };
  }, [page, pageCount]);

  return (
    <div className="flex h-full min-h-0 flex-col">
      <div className="flex items-center justify-center gap-3 border-b border-zinc-200 bg-white/60 px-4 py-2 text-[13px] font-semibold text-zinc-600 dark:border-white/10 dark:text-zinc-300">
        <button onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page <= 1} className="rounded-md p-1 hover:bg-zinc-100 disabled:opacity-30" aria-label="prev"><ChevronLeft className="h-4 w-4" /></button>
        {L("page", lang)} {page} {L("of", lang)} {pageCount} · {file.name} ({fmtBytes(file.size)})
        <button onClick={() => setPage((p) => Math.min(pageCount, p + 1))} disabled={page >= pageCount} className="rounded-md p-1 hover:bg-zinc-100 disabled:opacity-30" aria-label="next"><ChevronRight className="h-4 w-4" /></button>
        <a
          href={URL.createObjectURL(file)}
          download={file.name}
          className="ml-2 flex items-center gap-1.5 rounded-lg bg-[#0b7a43] px-3 py-1.5 text-[12.5px] font-bold text-white"
        >
          <Download className="h-3.5 w-3.5" /> {L("download", lang)}
        </a>
      </div>
      <div className="min-h-0 flex-1 overflow-auto bg-zinc-100 p-4 dark:bg-black/30">
        <div className="relative mx-auto w-fit">
          <div ref={hostRef} />
          {loading && <div className="flex h-80 w-[560px] max-w-[80vw] items-center justify-center rounded-lg bg-white"><Loader2 className="h-7 w-7 animate-spin text-emerald-600" /></div>}
        </div>
      </div>
    </div>
  );
}

/* =============== COLOR PICKER =============== */
export function ColorPickerTool({ file }: { file: File }) {
  const [colors, setColors] = useState<string[]>([]);
  const [ready, setReady] = useState(false);
  const imgRef = useRef<HTMLImageElement>(null);
  const [src, setSrc] = useState<string>("");

  useEffect(() => {
    (async () => {
      const el = await loadImageBitmapEl(file);
      const c = document.createElement("canvas");
      c.width = el.naturalWidth;
      c.height = el.naturalHeight;
      c.getContext("2d")!.drawImage(el, 0, 0);
      (imgRef.current as unknown as Record<string, unknown>)["_ctx"] = c;
      setReady(true);
    })();
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setSrc(URL.createObjectURL(file));
  }, [file]);

  const pick = (e: React.MouseEvent<HTMLImageElement>) => {
    const holder = imgRef.current as unknown as { _ctx?: HTMLCanvasElement } | null;
    const c = holder?._ctx;
    if (!c) return;
    const r = e.currentTarget.getBoundingClientRect();
    const x = Math.floor(((e.clientX - r.left) / r.width) * c.width);
    const y = Math.floor(((e.clientY - r.top) / r.height) * c.height);
    const d = c.getContext("2d")!.getImageData(x, y, 1, 1).data;
    const hex = `#${[d[0], d[1], d[2]].map((v) => v.toString(16).padStart(2, "0")).join("")}`;
    setColors((arr) => [hex, ...arr.filter((h) => h !== hex)].slice(0, 14));
  };

  return (
    <div className="flex h-full min-h-0 flex-col lg:flex-row">
      <div className="flex min-h-0 flex-1 items-center justify-center overflow-auto bg-zinc-100 p-6 dark:bg-black/30">
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img
          ref={imgRef}
          src={src}
          alt={file.name}
          onClick={pick}
          className={`max-h-full max-w-full cursor-crosshair rounded-lg shadow-md ${ready ? "" : "opacity-0"}`}
        />
      </div>
      <div className="w-full shrink-0 space-y-3 border-t border-zinc-200 p-4 dark:border-white/10 lg:w-72 lg:border-l lg:border-t-0">
        <div className="text-[13px] font-bold text-zinc-700 dark:text-zinc-200">Picked colours</div>
        {colors.length === 0 && <p className="text-[12.5px] text-zinc-400">Click the image to pick colours.</p>}
        {colors.map((c) => (
          <div key={c} className="flex items-center gap-3 rounded-lg border border-zinc-100 p-2 dark:border-white/10">
            <span className="h-8 w-8 rounded-md ring-1 ring-black/10" style={{ background: c }} />
            <code className="flex-1 text-[13px] font-semibold text-zinc-700 dark:text-zinc-200">{c}</code>
            <button onClick={() => navigator.clipboard.writeText(c)} className="rounded-md bg-zinc-100 px-2 py-1 text-[11.5px] font-bold text-zinc-600 hover:bg-zinc-200 dark:bg-white/10 dark:text-zinc-300">Copy</button>
          </div>
        ))}
      </div>
    </div>
  );
}
