'use client';

import { useCallback, useEffect, useRef, useState } from 'react';
import { Eraser, PenLine, Upload, Sparkles } from 'lucide-react';
import { cleanInk, inkBounds, inkRatio } from '@/lib/signature';

export type SignatureValue = { image: string; method: 'DRAW' | 'UPLOAD' } | null;

const PAD_W = 560;
const PAD_H = 200;

/** Crop a canvas region to its ink, scale to ≤ 600 px wide and return a transparent PNG data URL. */
function exportTrimmed(src: HTMLCanvasElement): string | null {
  const ctx = src.getContext('2d')!;
  const img = ctx.getImageData(0, 0, src.width, src.height);
  if (inkRatio(img.data) < 0.0015) return null; // blank
  const b = inkBounds(img.data, src.width, src.height);
  if (!b) return null;
  const pad = 8;
  const x = Math.max(0, b.x - pad), y = Math.max(0, b.y - pad);
  const w = Math.min(src.width - x, b.w + pad * 2), h = Math.min(src.height - y, b.h + pad * 2);
  const scale = Math.min(1, 600 / w);
  const out = document.createElement('canvas');
  out.width = Math.max(1, Math.round(w * scale)); out.height = Math.max(1, Math.round(h * scale));
  const octx = out.getContext('2d')!;
  octx.imageSmoothingQuality = 'high';
  octx.drawImage(src, x, y, w, h, 0, 0, out.width, out.height);
  return out.toDataURL('image/png');
}

/**
 * Two ways to sign, exactly one is used:
 *   Draw    — sign with the mouse / finger / pen on the pad.
 *   Upload  — pick a photo or scan, drag a box around the signature to crop it,
 *             then "Auto-clean" removes the paper and sharpens the ink.
 * Calls onChange with a transparent PNG (or null when empty).
 */
export default function SignaturePad({ value, onChange }: { value: SignatureValue; onChange: (v: SignatureValue) => void }) {
  const [tab, setTab] = useState<'DRAW' | 'UPLOAD'>('DRAW');

  // ── DRAW ────────────────────────────────────────────────────────────
  const pad = useRef<HTMLCanvasElement>(null);
  const drawing = useRef(false);
  const last = useRef<{ x: number; y: number } | null>(null);

  const pos = (e: React.PointerEvent<HTMLCanvasElement>) => {
    const r = e.currentTarget.getBoundingClientRect();
    return { x: ((e.clientX - r.left) / r.width) * PAD_W, y: ((e.clientY - r.top) / r.height) * PAD_H };
  };
  function down(e: React.PointerEvent<HTMLCanvasElement>) {
    drawing.current = true; e.currentTarget.setPointerCapture(e.pointerId);
    last.current = pos(e);
    const ctx = pad.current!.getContext('2d')!;
    ctx.beginPath(); ctx.arc(last.current.x, last.current.y, 1.2, 0, Math.PI * 2); ctx.fillStyle = '#0c183c'; ctx.fill();
  }
  function move(e: React.PointerEvent<HTMLCanvasElement>) {
    if (!drawing.current || !last.current) return;
    const p = pos(e); const ctx = pad.current!.getContext('2d')!;
    ctx.strokeStyle = '#0c183c'; ctx.lineWidth = 2.4; ctx.lineCap = 'round'; ctx.lineJoin = 'round';
    ctx.beginPath(); ctx.moveTo(last.current.x, last.current.y); ctx.lineTo(p.x, p.y); ctx.stroke();
    last.current = p;
  }
  function up() {
    if (!drawing.current) return;
    drawing.current = false; last.current = null;
    const png = exportTrimmed(pad.current!);
    onChange(png ? { image: png, method: 'DRAW' } : null);
  }
  function clearPad() {
    const c = pad.current; if (!c) return;
    c.getContext('2d')!.clearRect(0, 0, c.width, c.height);
    onChange(null);
  }

  // ── UPLOAD ──────────────────────────────────────────────────────────
  const preview = useRef<HTMLCanvasElement>(null);
  const [source, setSource] = useState<HTMLImageElement | null>(null);
  const [crop, setCrop] = useState<{ x: number; y: number; w: number; h: number } | null>(null); // in preview px
  const dragStart = useRef<{ x: number; y: number } | null>(null);
  const [sensitivity, setSensitivity] = useState(0.5);
  const [cleaned, setCleaned] = useState(false);
  const scaleRef = useRef(1);

  function pickFile(file: File | undefined) {
    if (!file) return;
    const url = URL.createObjectURL(file);
    const img = new Image();
    img.onload = () => { setSource(img); setCrop(null); setCleaned(false); onChange(null); URL.revokeObjectURL(url); };
    img.src = url;
  }

  // Draw the uploaded image (with crop box) into the preview canvas.
  useEffect(() => {
    const c = preview.current; if (!c || !source) return;
    const maxW = 560;
    const s = Math.min(1, maxW / source.width);
    scaleRef.current = s;
    c.width = Math.round(source.width * s); c.height = Math.round(source.height * s);
    const ctx = c.getContext('2d')!;
    ctx.clearRect(0, 0, c.width, c.height);
    ctx.drawImage(source, 0, 0, c.width, c.height);
    if (crop) {
      ctx.fillStyle = 'rgba(0,0,0,0.35)';
      ctx.fillRect(0, 0, c.width, c.height);
      ctx.drawImage(source, crop.x / s, crop.y / s, crop.w / s, crop.h / s, crop.x, crop.y, crop.w, crop.h);
      ctx.strokeStyle = '#C1272D'; ctx.lineWidth = 2; ctx.setLineDash([6, 4]); ctx.strokeRect(crop.x, crop.y, crop.w, crop.h);
    }
  }, [source, crop]);

  const pPos = (e: React.PointerEvent<HTMLCanvasElement>) => {
    const r = e.currentTarget.getBoundingClientRect();
    return { x: ((e.clientX - r.left) / r.width) * e.currentTarget.width, y: ((e.clientY - r.top) / r.height) * e.currentTarget.height };
  };

  const runClean = useCallback(() => {
    if (!source) return;
    const s = scaleRef.current;
    // Crop in ORIGINAL image pixels; whole image if no box was drawn.
    const c = crop && crop.w > 10 && crop.h > 10 ? { x: crop.x / s, y: crop.y / s, w: crop.w / s, h: crop.h / s } : { x: 0, y: 0, w: source.width, h: source.height };
    const k = Math.min(1, 900 / c.w); // work at ≤ 900 px wide
    const work = document.createElement('canvas');
    work.width = Math.max(1, Math.round(c.w * k)); work.height = Math.max(1, Math.round(c.h * k));
    const ctx = work.getContext('2d', { willReadFrequently: true })!;
    ctx.imageSmoothingQuality = 'high';
    ctx.drawImage(source, c.x, c.y, c.w, c.h, 0, 0, work.width, work.height);
    const img = ctx.getImageData(0, 0, work.width, work.height);
    cleanInk(img.data, work.width, work.height, sensitivity);
    ctx.putImageData(img, 0, 0);
    const png = exportTrimmed(work);
    setCleaned(!!png);
    onChange(png ? { image: png, method: 'UPLOAD' } : null);
  }, [source, crop, sensitivity, onChange]);

  // Re-run when the sensitivity slider moves (after the first clean).
  useEffect(() => { if (cleaned) runClean(); }, [sensitivity]); // eslint-disable-line react-hooks/exhaustive-deps

  return (
    <div className="border border-brand-border rounded-xl p-3 bg-white">
      <div className="flex gap-1 mb-3">
        {([['DRAW', PenLine, 'Draw signature'], ['UPLOAD', Upload, 'Upload & clean up']] as const).map(([k, Icon, label]) => (
          <button key={k} type="button" onClick={() => setTab(k)}
            className={`flex items-center gap-1.5 text-xs font-semibold px-3 py-1.5 rounded-lg transition-colors ${tab === k ? 'bg-brand-charcoal text-white' : 'bg-brand-bg text-gray-600 hover:bg-gray-100'}`}>
            <Icon size={13} /> {label}
          </button>
        ))}
      </div>

      {tab === 'DRAW' && (
        <div>
          <canvas ref={pad} width={PAD_W} height={PAD_H}
            onPointerDown={down} onPointerMove={move} onPointerUp={up} onPointerCancel={up} onPointerLeave={up}
            className="w-full rounded-lg border border-dashed border-gray-300 bg-[repeating-linear-gradient(transparent,transparent_38px,#eee_39px)] cursor-crosshair"
            style={{ touchAction: 'none', aspectRatio: `${PAD_W} / ${PAD_H}` }} />
          <div className="flex items-center justify-between mt-2">
            <p className="text-[10px] text-gray-400">Sign inside the box with your mouse, finger or pen.</p>
            <button type="button" onClick={clearPad} className="flex items-center gap-1 text-[11px] text-gray-500 hover:text-brand-red"><Eraser size={12} /> Clear</button>
          </div>
        </div>
      )}

      {tab === 'UPLOAD' && (
        <div className="space-y-2">
          <label className="inline-flex items-center gap-1.5 border border-dashed border-brand-border rounded-lg px-3 py-2 text-xs cursor-pointer hover:bg-brand-bg">
            <Upload size={13} /> {source ? 'Choose a different image' : 'Choose a photo or scan of your signature'}
            <input type="file" accept="image/png,image/jpeg,image/webp" className="hidden" onChange={(e) => { pickFile(e.target.files?.[0]); e.target.value = ''; }} />
          </label>
          {source && (
            <>
              <p className="text-[10px] text-gray-400">Drag a box around just the signature to crop it, then press Auto-clean.</p>
              <canvas ref={preview} className="w-full rounded-lg border border-brand-border cursor-crosshair bg-[conic-gradient(#eee_25%,#fff_0_50%,#eee_0_75%,#fff_0)] bg-[length:16px_16px]"
                style={{ touchAction: 'none' }}
                onPointerDown={(e) => { e.currentTarget.setPointerCapture(e.pointerId); dragStart.current = pPos(e); setCrop({ ...dragStart.current, w: 0, h: 0 }); }}
                onPointerMove={(e) => {
                  if (!dragStart.current) return; const p = pPos(e); const s = dragStart.current;
                  setCrop({ x: Math.min(s.x, p.x), y: Math.min(s.y, p.y), w: Math.abs(p.x - s.x), h: Math.abs(p.y - s.y) });
                }}
                onPointerUp={() => { dragStart.current = null; }} />
              <div className="flex items-center gap-3">
                <button type="button" onClick={runClean} className="flex items-center gap-1.5 bg-brand-red text-white text-xs font-semibold px-3 py-1.5 rounded-lg">
                  <Sparkles size={13} /> Auto-clean
                </button>
                <label className="flex items-center gap-2 text-[11px] text-gray-500">
                  Ink strength
                  <input type="range" min={0} max={1} step={0.05} value={sensitivity} onChange={(e) => setSensitivity(Number(e.target.value))} />
                </label>
              </div>
              {cleaned === false && value === null && <p className="text-[10px] text-gray-400">Auto-clean removes the paper background and sharpens the ink so the signature sits cleanly on the letter.</p>}
            </>
          )}
        </div>
      )}

      {value && (
        <div className="mt-3 border-t border-brand-border pt-3">
          <p className="text-[10px] uppercase tracking-wide text-gray-400 mb-1">This is how it will appear on the letter</p>
          <div className="inline-block bg-white border border-brand-border rounded-lg p-3">
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img src={value.image} alt="Signature preview" className="h-14 object-contain" />
          </div>
        </div>
      )}
    </div>
  );
}
