"use client";

import { useEffect, useRef, useState } from "react";
import { Eraser, Loader2, Paintbrush, Undo2 } from "lucide-react";
import type { PecaDeImagem } from "@/lib/banner-editor/documento";
import { fotoNaCaixa } from "@/lib/banner-editor/tirar-fundo";

/*
  A borracha da foto (para limpar restos do "tirar fundo", como confete ou
  sombra que ficou): pinta por cima da foto, do tamanho certo dela. "Apagar"
  tira os pixels; "Restaurar" traz de volta da foto original (a de antes de
  tirar o fundo). Pronto devolve a foto nova (o editor sobe e troca).
*/

type Modo = "apagar" | "restaurar";

async function carregar(src: string) {
  const img = new Image();
  img.crossOrigin = "anonymous";
  img.src = src;
  await img.decode();
  return img;
}

export function Borracha({ foto, escala, aoPronto, aoCancelar }: { foto: PecaDeImagem; escala: number; aoPronto: (arquivo: File) => Promise<void>; aoCancelar: () => void }) {
  const tela = useRef<HTMLCanvasElement | null>(null);
  const original = useRef<HTMLImageElement | null>(null);
  const historico = useRef<ImageData[]>([]);
  const ultimo = useRef<{ x: number; y: number } | null>(null);
  const [modo, setModo] = useState<Modo>("apagar");
  const [tamanho, setTamanho] = useState(36);
  const [natural, setNatural] = useState<{ w: number; h: number } | null>(null);
  const [cursor, setCursor] = useState<{ x: number; y: number } | null>(null);
  const [erro, setErro] = useState<string | null>(null);
  const [salvando, setSalvando] = useState(false);
  const [desfazeres, setDesfazeres] = useState(0);

  /* A foto de agora na tela de pintura; a original (se houver) guardada para o "Restaurar". */
  useEffect(() => {
    let vivo = true;
    (async () => {
      try {
        const img = await carregar(foto.src);
        if (!vivo || !tela.current) return;
        tela.current.width = img.naturalWidth;
        tela.current.height = img.naturalHeight;
        const c = tela.current.getContext("2d", { willReadFrequently: true })!;
        c.drawImage(img, 0, 0);
        c.getImageData(0, 0, 1, 1);
        setNatural({ w: img.naturalWidth, h: img.naturalHeight });
        if (foto.semFundoDe) original.current = await carregar(foto.semFundoDe).catch(() => null);
      } catch {
        if (vivo) setErro("Essa foto vem de outro site e o navegador não deixa pintar nela. Envie a foto pelo botão Enviar imagem.");
      }
    })();
    return () => {
      vivo = false;
    };
  }, [foto.src, foto.semFundoDe]);

  const naCaixa = natural ? fotoNaCaixa(foto, natural) : null;
  /* Quantos px da tela de pintura cabem em 1 px da tela do computador. */
  const proporcao = naCaixa && natural ? natural.w / Math.max(1, naCaixa.w * escala) : 1;

  const pontoNaFoto = (e: React.PointerEvent) => {
    const r = tela.current!.getBoundingClientRect();
    return { x: ((e.clientX - r.left) / r.width) * tela.current!.width, y: ((e.clientY - r.top) / r.height) * tela.current!.height };
  };

  /* Uma pincelada de A até B: círculos no caminho, apagando ou trazendo a original de volta. */
  const pintar = (a: { x: number; y: number }, b: { x: number; y: number }) => {
    const c = tela.current?.getContext("2d");
    if (!c || !natural) return;
    const r = (tamanho / 2) * proporcao;
    const caminho = new Path2D();
    const passos = Math.max(1, Math.ceil(Math.hypot(b.x - a.x, b.y - a.y) / (r / 3)));
    for (let i = 0; i <= passos; i++) {
      const x = a.x + ((b.x - a.x) * i) / passos;
      const y = a.y + ((b.y - a.y) * i) / passos;
      caminho.moveTo(x + r, y);
      caminho.arc(x, y, r, 0, Math.PI * 2);
    }
    c.save();
    c.clip(caminho);
    if (modo === "apagar") c.clearRect(0, 0, natural.w, natural.h);
    else if (original.current) {
      /* A foto de agora é um pedaço da original (o corte do "tirar fundo"). */
      const corte = foto.corteDoFundo ?? { x0: 0, y0: 0, x1: 1, y1: 1 };
      const o = original.current;
      c.clearRect(0, 0, natural.w, natural.h);
      c.drawImage(o, corte.x0 * o.naturalWidth, corte.y0 * o.naturalHeight, (corte.x1 - corte.x0) * o.naturalWidth, (corte.y1 - corte.y0) * o.naturalHeight, 0, 0, natural.w, natural.h);
    }
    c.restore();
  };

  const comecar = (e: React.PointerEvent) => {
    if (e.button !== 0 || !tela.current || erro) return;
    e.stopPropagation();
    e.preventDefault();
    (e.target as Element).setPointerCapture(e.pointerId);
    const c = tela.current.getContext("2d")!;
    historico.current = [...historico.current.slice(-9), c.getImageData(0, 0, tela.current.width, tela.current.height)];
    setDesfazeres(historico.current.length);
    const p = pontoNaFoto(e);
    ultimo.current = p;
    pintar(p, p);
  };
  const mover = (e: React.PointerEvent) => {
    const r = tela.current?.getBoundingClientRect();
    if (r) setCursor({ x: e.clientX - r.left, y: e.clientY - r.top });
    if (!ultimo.current) return;
    const p = pontoNaFoto(e);
    pintar(ultimo.current, p);
    ultimo.current = p;
  };
  const soltar = () => {
    ultimo.current = null;
  };
  const desfazer = () => {
    const antes = historico.current.pop();
    if (antes) tela.current?.getContext("2d")?.putImageData(antes, 0, 0);
    setDesfazeres(historico.current.length);
  };
  const pronto = async () => {
    if (!tela.current) return;
    setSalvando(true);
    const blob = await new Promise<Blob | null>((r) => tela.current!.toBlob(r, "image/webp", 0.92));
    const arquivo = blob && blob.type === "image/webp" ? blob : await new Promise<Blob | null>((r) => tela.current!.toBlob(r, "image/png"));
    if (!arquivo) {
      setSalvando(false);
      setErro("Não deu para montar a foto.");
      return;
    }
    await aoPronto(new File([arquivo], `limpa.${arquivo.type === "image/webp" ? "webp" : "png"}`, { type: arquivo.type }));
    setSalvando(false);
  };

  return (
    <>
      <div className="pointer-events-auto absolute inset-0 overflow-hidden" style={{ background: "repeating-conic-gradient(#E5E2EE 0% 25%, #FFFFFF 0% 50%) 0 0/16px 16px", touchAction: "none" }} data-borracha={foto.id}>
        <canvas
          ref={tela}
          onPointerDown={comecar}
          onPointerMove={mover}
          onPointerUp={soltar}
          onPointerCancel={soltar}
          onPointerLeave={() => setCursor(null)}
          className="absolute block"
          style={naCaixa ? { left: naCaixa.x * escala, top: naCaixa.y * escala, width: naCaixa.w * escala, height: naCaixa.h * escala, cursor: "none" } : { inset: 0 }}
        />
        {cursor && naCaixa ? (
          <span className="pointer-events-none absolute rounded-full border-2 border-white shadow-[0_0_0_1px_rgba(0,0,0,0.5)]" style={{ left: naCaixa.x * escala + cursor.x - tamanho / 2, top: naCaixa.y * escala + cursor.y - tamanho / 2, width: tamanho, height: tamanho, background: modo === "apagar" ? "rgba(244,63,94,0.18)" : "rgba(34,197,94,0.18)" }} />
        ) : null}
      </div>
      <div
        className="pointer-events-auto absolute left-1/2 flex items-center gap-2 whitespace-nowrap rounded-[12px] bg-white px-3 py-2 shadow-[0_8px_30px_rgba(20,11,43,0.22)] ring-1 ring-black/5"
        style={{ top: -64, transform: `translateX(-50%) rotate(${-foto.rot}deg)` }}
        onPointerDown={(e) => e.stopPropagation()}
        data-barra-da-borracha
      >
        {erro ? <span className="max-w-[320px] whitespace-normal text-[12px] font-semibold text-[#BE123C]">{erro}</span> : null}
        <button type="button" aria-pressed={modo === "apagar"} onClick={() => setModo("apagar")} className={`flex h-8 items-center gap-1.5 rounded-[8px] px-2.5 text-[12px] font-bold ${modo === "apagar" ? "bg-[#7C3AED] text-white" : "text-[#4B4760] hover:bg-[#F1EFF6]"}`}>
          <Eraser size={14} /> Apagar
        </button>
        <button type="button" aria-pressed={modo === "restaurar"} disabled={!foto.semFundoDe} title={foto.semFundoDe ? "Pinta de volta com a foto original" : "Só depois de tirar o fundo (precisa da foto original)"} onClick={() => setModo("restaurar")} className={`flex h-8 items-center gap-1.5 rounded-[8px] px-2.5 text-[12px] font-bold disabled:opacity-40 ${modo === "restaurar" ? "bg-[#16A34A] text-white" : "text-[#4B4760] hover:bg-[#F1EFF6]"}`}>
          <Paintbrush size={14} /> Restaurar
        </button>
        <span className="text-[11.5px] font-semibold text-[#4B4760]">Pincel</span>
        <input type="range" min={8} max={140} value={tamanho} onChange={(e) => setTamanho(Number(e.target.value))} className="w-24 accent-[#7C3AED]" aria-label="Tamanho do pincel" />
        <button type="button" title="Desfazer a última pincelada" disabled={!desfazeres} onClick={desfazer} className="flex h-8 w-8 items-center justify-center rounded-[8px] text-[#4B4760] hover:bg-[#F1EFF6] disabled:opacity-35">
          <Undo2 size={15} />
        </button>
        <button type="button" onClick={aoCancelar} className="rounded-[8px] px-2.5 py-1 text-[12px] font-semibold text-[#6B6584] hover:bg-[#F1EFF6]">
          Cancelar
        </button>
        <button type="button" disabled={salvando || Boolean(erro)} onClick={() => void pronto()} className="flex items-center gap-1.5 rounded-[8px] bg-[#7C3AED] px-3 py-1 text-[12px] font-bold text-white hover:bg-[#6D28D9] disabled:opacity-60">
          {salvando ? <Loader2 size={13} className="animate-spin" /> : null} Pronto
        </button>
      </div>
    </>
  );
}
