import { useState, useRef, useCallback, useEffect } from "react";
import { Upload, Download, X, Lock, Unlock, ImageIcon, Maximize2 } from "lucide-react";
import { cn } from "../lib/utils";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const CHECKERBOARD: React.CSSProperties = {
  backgroundImage: `
    linear-gradient(45deg, #444 25%, transparent 25%),
    linear-gradient(-45deg, #444 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #444 75%),
    linear-gradient(-45deg, transparent 75%, #444 75%)
  `,
  backgroundSize: "16px 16px",
  backgroundPosition: "0 0, 0 8px, 8px -8px, -8px 0px",
  backgroundColor: "#2a2a2a",
};

type BgPreset = { label: string; style: React.CSSProperties };

const BG_PRESETS: BgPreset[] = [
  { label: "Checker", style: CHECKERBOARD },
  { label: "White",   style: { backgroundColor: "#ffffff" } },
  { label: "Black",   style: { backgroundColor: "#000000" } },
  { label: "Red",     style: { backgroundColor: "#e53e3e" } },
  { label: "Green",   style: { backgroundColor: "#38a169" } },
  { label: "Blue",    style: { backgroundColor: "#3182ce" } },
];

type ScaleMode = "fit" | "fill" | "stretch" | "original";

const SCALE_MODES: { id: ScaleMode; label: string; desc: string }[] = [
  { id: "fit",      label: "Fit",      desc: "Scale to fit canvas, preserve ratio (letterbox)" },
  { id: "fill",     label: "Fill",     desc: "Scale to fill canvas, preserve ratio (crop edges)" },
  { id: "stretch",  label: "Stretch",  desc: "Stretch to exact dimensions, ignore ratio" },
  { id: "original", label: "Original", desc: "No scaling — align/center only" },
];

type Align = [-1 | 0 | 1, -1 | 0 | 1];

const ALIGN_GRID: Align[] = [
  [-1, -1], [0, -1], [1, -1],
  [-1,  0], [0,  0], [1,  0],
  [-1,  1], [0,  1], [1,  1],
];

const SIZE_PRESETS: { label: string; w: number; h: number }[] = [
  { label: "64",        w: 64,   h: 64   },
  { label: "128",       w: 128,  h: 128  },
  { label: "256",       w: 256,  h: 256  },
  { label: "512",       w: 512,  h: 512  },
  { label: "1024",      w: 1024, h: 1024 },
  { label: "960×540",   w: 960,  h: 540  },
  { label: "1920×1080", w: 1920, h: 1080 },
];

// ---------------------------------------------------------------------------
// CanvasTool
// ---------------------------------------------------------------------------

export function CanvasTool() {
  const [imageSrc,   setImageSrc]   = useState<string | null>(null);
  const [imageFile,  setImageFile]  = useState<File | null>(null);
  const [imageReady, setImageReady] = useState(false);
  const [dragOver,   setDragOver]   = useState(false);

  const [naturalW, setNaturalW] = useState(1);
  const [naturalH, setNaturalH] = useState(1);

  const [outW,        setOutW]        = useState("256");
  const [outH,        setOutH]        = useState("256");
  const [aspectLock,  setAspectLock]  = useState(true);
  const [scaleMode,   setScaleMode]   = useState<ScaleMode>("fit");
  const [alignment,   setAlignment]   = useState<Align>([0, 0]);
  const [bgPreset,    setBgPreset]    = useState(0);

  const fileInputRef    = useRef<HTMLInputElement>(null);
  const sourceCanvasRef = useRef<HTMLCanvasElement>(null);
  // previewCanvasRef — drawn to directly on every setting change; no toDataURL
  const previewCanvasRef = useRef<HTMLCanvasElement>(null);

  // ── Load image onto hidden source canvas ──────────────────────────────────
  useEffect(() => {
    if (!imageSrc) return;
    setImageReady(false);

    const img = new Image();
    img.onload = () => {
      const canvas = sourceCanvasRef.current;
      if (!canvas) return;
      canvas.width  = img.naturalWidth;
      canvas.height = img.naturalHeight;
      canvas.getContext("2d")!.drawImage(img, 0, 0);
      setNaturalW(img.naturalWidth);
      setNaturalH(img.naturalHeight);
      setOutW(String(img.naturalWidth));
      setOutH(String(img.naturalHeight));
      setImageReady(true);
    };
    img.src = imageSrc;
  }, [imageSrc]);

  // ── Draw output directly into previewCanvasRef whenever settings change ────
  // drawImage is GPU-accelerated; skipping toDataURL eliminates the main bottleneck.
  useEffect(() => {
    if (!imageReady) return;
    const src = sourceCanvasRef.current;
    const prev = previewCanvasRef.current;
    if (!src || !prev) return;

    const w = parseInt(outW);
    const h = parseInt(outH);
    if (!w || !h || w <= 0 || h <= 0) return;

    const frame = requestAnimationFrame(() => {
      prev.width  = w;
      prev.height = h;
      const ctx = prev.getContext("2d")!;
      ctx.clearRect(0, 0, w, h);

      const srcW = src.width;
      const srcH = src.height;

      let drawW: number;
      let drawH: number;

      if (scaleMode === "fit") {
        const scale = Math.min(w / srcW, h / srcH);
        drawW = srcW * scale;
        drawH = srcH * scale;
      } else if (scaleMode === "fill") {
        const scale = Math.max(w / srcW, h / srcH);
        drawW = srcW * scale;
        drawH = srcH * scale;
      } else if (scaleMode === "stretch") {
        drawW = w;
        drawH = h;
      } else {
        drawW = srcW;
        drawH = srcH;
      }

      const x = (w - drawW) * (alignment[0] + 1) / 2;
      const y = (h - drawH) * (alignment[1] + 1) / 2;

      ctx.drawImage(src, x, y, drawW, drawH);
    });

    return () => cancelAnimationFrame(frame);
  }, [imageReady, outW, outH, scaleMode, alignment]);

  // ── Width / height with optional aspect lock ───────────────────────────────
  const handleWChange = (v: string) => {
    setOutW(v);
    if (aspectLock) {
      const n = parseInt(v);
      if (!isNaN(n) && n > 0) setOutH(String(Math.round(n * naturalH / naturalW)));
    }
  };

  const handleHChange = (v: string) => {
    setOutH(v);
    if (aspectLock) {
      const n = parseInt(v);
      if (!isNaN(n) && n > 0) setOutW(String(Math.round(n * naturalW / naturalH)));
    }
  };

  // ── File loading ───────────────────────────────────────────────────────────
  const loadFile = useCallback((file: File) => {
    if (imageSrc) URL.revokeObjectURL(imageSrc);
    setImageSrc(URL.createObjectURL(file));
    setImageFile(file);
  }, [imageSrc]);

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(false);
    const file = e.dataTransfer.files[0];
    if (file?.type.startsWith("image/")) loadFile(file);
  };

  // Download: toBlob from previewCanvasRef — only at explicit user request
  const handleDownload = () => {
    const prev = previewCanvasRef.current;
    if (!prev || !imageReady || !imageFile) return;
    prev.toBlob((blob) => {
      if (!blob) return;
      const url = URL.createObjectURL(blob);
      const a   = document.createElement("a");
      a.download = imageFile.name.replace(/\.[^.]+$/, "") + `_${outW}x${outH}.png`;
      a.href = url;
      a.click();
      URL.revokeObjectURL(url);
    }, "image/png");
  };

  const clearAll = useCallback(() => {
    if (imageSrc) URL.revokeObjectURL(imageSrc);
    setImageSrc(null);
    setImageFile(null);
    setImageReady(false);
    if (fileInputRef.current) fileInputRef.current.value = "";
  }, [imageSrc]);

  // ── Upload screen ──────────────────────────────────────────────────────────
  if (!imageSrc) {
    return (
      <div className="max-w-2xl mx-auto py-8 space-y-4">
        <div>
          <h2 className="text-lg font-semibold text-foreground mb-1">Canvas Tool</h2>
          <p className="text-sm text-text-secondary">
            Upload an image to resize, scale, or center it on a canvas of any size.
          </p>
        </div>

        <div
          onDrop={handleDrop}
          onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
          onDragLeave={() => setDragOver(false)}
          onClick={() => fileInputRef.current?.click()}
          className={cn(
            "border-2 border-dashed rounded-xl p-16 flex flex-col items-center gap-4 cursor-pointer transition-all select-none",
            dragOver
              ? "border-primary bg-primary/5"
              : "border-border hover:border-primary/50 hover:bg-primary/3",
          )}
        >
          <Upload className={cn("w-10 h-10 transition-colors", dragOver ? "text-primary" : "text-text-tertiary")} />
          <div className="text-center">
            <p className="text-sm font-medium text-text-secondary">
              {dragOver ? "Drop to upload" : "Drop an image here"}
            </p>
            <p className="text-xs text-text-tertiary mt-1">
              or click to browse · PNG, JPEG, WebP · max 15 MB
            </p>
          </div>
        </div>

        <input
          ref={fileInputRef}
          type="file"
          accept="image/png,image/jpeg,image/webp"
          onChange={(e) => { const f = e.target.files?.[0]; if (f) loadFile(f); }}
          className="hidden"
        />
      </div>
    );
  }

  // ── Editor screen ──────────────────────────────────────────────────────────
  const alignDisabled = scaleMode === "stretch";

  return (
    <div className="space-y-4 pb-8">
      {/* Hidden source canvas */}
      <canvas ref={sourceCanvasRef} className="hidden" />

      {/* Toolbar */}
      <div className="flex items-center gap-3 flex-wrap">
        <h2 className="text-lg font-semibold text-foreground flex-1">Canvas Tool</h2>
        <span className="text-xs text-text-tertiary font-mono truncate max-w-[200px]">
          {imageFile?.name}
        </span>
        <span className="text-xs text-text-tertiary font-mono">
          {naturalW}×{naturalH}
        </span>
        <button
          onClick={clearAll}
          className={cn(
            "flex items-center gap-1.5 px-3 py-1.5 rounded-md border border-border text-xs text-text-tertiary",
            "hover:text-destructive hover:border-destructive transition-colors",
          )}
        >
          <X className="w-3.5 h-3.5" /> Clear
        </button>
        <button
          onClick={handleDownload}
          disabled={!imageReady}
          className={cn(
            "flex items-center gap-1.5 px-4 py-1.5 rounded-md text-xs font-semibold transition-colors",
            imageReady
              ? "bg-primary text-white hover:bg-primary/90"
              : "bg-raised border border-border text-text-tertiary cursor-not-allowed",
          )}
        >
          <Download className="w-3.5 h-3.5" /> Download PNG
        </button>
      </div>

      {/* Controls */}
      <div className="bg-card border border-border rounded-xl p-4 space-y-4">
        {/* Row 1: output size */}
        <div className="flex flex-wrap gap-4 items-end">
          <div className="space-y-1.5">
            <p className="text-xs font-medium text-text-secondary">Output Size</p>
            <div className="flex items-center gap-2">
              <input
                type="number" min="1" max="4096" value={outW}
                onChange={(e) => handleWChange(e.target.value)}
                className={cn(
                  "w-20 bg-input border border-border rounded-md px-2 py-1.5 text-sm text-foreground font-mono",
                  "focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary/30",
                )}
                placeholder="W"
              />
              <span className="text-text-tertiary text-xs">×</span>
              <input
                type="number" min="1" max="4096" value={outH}
                onChange={(e) => handleHChange(e.target.value)}
                className={cn(
                  "w-20 bg-input border border-border rounded-md px-2 py-1.5 text-sm text-foreground font-mono",
                  "focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary/30",
                )}
                placeholder="H"
              />
              <button
                onClick={() => setAspectLock((l) => !l)}
                title={aspectLock ? "Unlock aspect ratio" : "Lock aspect ratio"}
                className={cn(
                  "p-1.5 rounded-md border transition-colors",
                  aspectLock
                    ? "border-primary text-primary bg-primary/10"
                    : "border-border text-text-tertiary hover:border-primary/50",
                )}
              >
                {aspectLock ? <Lock className="w-3.5 h-3.5" /> : <Unlock className="w-3.5 h-3.5" />}
              </button>
            </div>
          </div>

          {/* Size presets */}
          <div className="space-y-1.5">
            <p className="text-xs font-medium text-text-secondary">Presets</p>
            <div className="flex flex-wrap gap-1">
              <button
                onClick={() => { setOutW(String(naturalW)); setOutH(String(naturalH)); }}
                className={cn(
                  "px-2 py-1 rounded text-xs border transition-colors",
                  outW === String(naturalW) && outH === String(naturalH)
                    ? "border-primary text-primary bg-primary/10"
                    : "border-border text-text-tertiary hover:border-primary/50 hover:text-foreground",
                )}
              >
                Original
              </button>
              {SIZE_PRESETS.map((p) => (
                <button
                  key={p.label}
                  onClick={() => {
                    if (aspectLock) {
                      const scale = Math.min(p.w / naturalW, p.h / naturalH);
                      setOutW(String(Math.round(naturalW * scale)));
                      setOutH(String(Math.round(naturalH * scale)));
                    } else {
                      setOutW(String(p.w));
                      setOutH(String(p.h));
                    }
                  }}
                  className={cn(
                    "px-2 py-1 rounded text-xs border transition-colors",
                    outW === String(p.w) && outH === String(p.h)
                      ? "border-primary text-primary bg-primary/10"
                      : "border-border text-text-tertiary hover:border-primary/50 hover:text-foreground",
                  )}
                >
                  {p.label}
                </button>
              ))}
            </div>
          </div>
        </div>

        {/* Row 2: scale mode + alignment */}
        <div className="flex flex-wrap gap-6 items-start">
          <div className="space-y-1.5">
            <p className="text-xs font-medium text-text-secondary">Scale Mode</p>
            <div className="flex gap-1">
              {SCALE_MODES.map((m) => (
                <button
                  key={m.id}
                  onClick={() => setScaleMode(m.id)}
                  title={m.desc}
                  className={cn(
                    "px-3 py-1.5 rounded-md text-xs font-medium border transition-colors",
                    scaleMode === m.id
                      ? "border-primary text-primary bg-primary/10"
                      : "border-border text-text-tertiary hover:border-primary/50 hover:text-foreground",
                  )}
                >
                  {m.label}
                </button>
              ))}
            </div>
            <p className="text-xs text-text-tertiary">
              {SCALE_MODES.find((m) => m.id === scaleMode)?.desc}
            </p>
          </div>

          <div className={cn("space-y-1.5", alignDisabled && "opacity-40 pointer-events-none")}>
            <p className="text-xs font-medium text-text-secondary">
              {scaleMode === "fill" ? "Crop Position" : "Alignment"}
            </p>
            <div className="grid grid-cols-3 gap-0.5 w-fit">
              {ALIGN_GRID.map(([col, row], i) => {
                const active = alignment[0] === col && alignment[1] === row;
                return (
                  <button
                    key={i}
                    onClick={() => setAlignment([col, row])}
                    title={`${row === -1 ? "Top" : row === 0 ? "Middle" : "Bottom"}-${col === -1 ? "Left" : col === 0 ? "Center" : "Right"}`}
                    className={cn(
                      "w-7 h-7 rounded flex items-center justify-center border transition-colors",
                      active
                        ? "border-primary bg-primary/20"
                        : "border-border hover:border-primary/50",
                    )}
                  >
                    <span className={cn(
                      "w-2 h-2 rounded-full transition-colors",
                      active ? "bg-primary" : "bg-text-tertiary/40",
                    )} />
                  </button>
                );
              })}
            </div>
          </div>
        </div>
      </div>

      {/* Side-by-side preview */}
      <div className="grid grid-cols-2 gap-4">
        {/* Original */}
        <div className="space-y-2">
          <p className="text-xs font-semibold text-text-tertiary uppercase tracking-wider">
            Original — {naturalW}×{naturalH}
          </p>
          <div className="bg-card border border-border rounded-lg overflow-hidden">
            <div style={CHECKERBOARD}>
              <img src={imageSrc} alt="Source" className="w-full block" />
            </div>
          </div>
        </div>

        {/* Result — canvas drawn directly, no toDataURL */}
        <div className="space-y-2">
          <div className="flex items-center gap-2 flex-wrap">
            <p className="text-xs font-semibold text-text-tertiary uppercase tracking-wider flex-1">
              Result — {outW || "?"}×{outH || "?"}
            </p>
            <div className="flex items-center gap-1">
              {BG_PRESETS.map((preset, i) => (
                <button
                  key={preset.label}
                  title={preset.label}
                  onClick={() => setBgPreset(i)}
                  className={cn(
                    "w-5 h-5 rounded border transition-all",
                    i === bgPreset
                      ? "ring-2 ring-primary ring-offset-1 ring-offset-background border-transparent"
                      : "border-border hover:border-primary/50",
                  )}
                  style={preset.style}
                />
              ))}
            </div>
          </div>
          <div className="bg-card border border-border rounded-lg overflow-hidden">
            <div style={BG_PRESETS[bgPreset].style} className={cn("w-full", !imageReady && "hidden")}>
              <canvas ref={previewCanvasRef} className="w-full block" />
            </div>
            {!imageReady && (
              <div className="aspect-square flex flex-col items-center justify-center text-text-tertiary gap-3 p-8">
                <ImageIcon className="w-10 h-10 opacity-20" />
                <span className="text-xs opacity-40 text-center leading-relaxed">
                  Loading image…
                </span>
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Info strip */}
      {imageReady && (
        <div className="flex items-center gap-2 text-xs text-text-tertiary">
          <Maximize2 className="w-3.5 h-3.5 shrink-0" />
          <span>
            Output: <span className="font-mono text-foreground">{outW}×{outH} px</span>
            {" · "}
            Mode: <span className="text-foreground capitalize">{scaleMode}</span>
            {scaleMode !== "stretch" && (
              <>
                {" · "}
                Align:{" "}
                <span className="text-foreground">
                  {alignment[1] === -1 ? "Top" : alignment[1] === 0 ? "Middle" : "Bottom"}
                  -{alignment[0] === -1 ? "Left" : alignment[0] === 0 ? "Center" : "Right"}
                </span>
              </>
            )}
          </span>
        </div>
      )}
    </div>
  );
}
