"use client";

import React, { useState, useRef, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
import {
  Upload, Download, CircleNotch, CheckCircle, XCircle, Repeat, WarningCircle,
} from "@/lib/icons";
import { toast } from "sonner";

// ── Types ──────────────────────────────────────────────────────────────────

type Position =
  | "top-left" | "top-center" | "top-right"
  | "middle-left" | "center" | "middle-right"
  | "bottom-left" | "bottom-center" | "bottom-right"
  | "tiled";

const GRID: Position[][] = [
  ["top-left", "top-center", "top-right"],
  ["middle-left", "center", "middle-right"],
  ["bottom-left", "bottom-center", "bottom-right"],
];

const POS_LABELS: Record<Position, string> = {
  "top-left": "Sol Üst", "top-center": "Üst Orta", "top-right": "Sağ Üst",
  "middle-left": "Sol Orta", "center": "Merkez", "middle-right": "Sağ Orta",
  "bottom-left": "Sol Alt", "bottom-center": "Alt Orta", "bottom-right": "Sağ Alt",
  "tiled": "Tekrar",
};

interface WatermarkPrefs {
  position: Position;
  logoSizePct: number;   // 5–40
  logoOpacity: number;   // 10–100
  bgEnabled: boolean;
  bgOpacity: number;     // 10–60
  bgColor: "white" | "dark";
}

const DEFAULT_PREFS: WatermarkPrefs = {
  position: "bottom-right",
  logoSizePct: 20,
  logoOpacity: 100,
  bgEnabled: true,
  bgOpacity: 25,
  bgColor: "white",
};

const PREFS_KEY = "kovak-wm-prefs-v1";

interface WFile {
  id: string;
  file: File;
  originalUrl: string;
  blob?: Blob;
  status: "idle" | "processing" | "done" | "error";
}

// ── Canvas helpers ──────────────────────────────────────────────────────────

function loadImg(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  });
}


type FixedPos = Exclude<Position, "tiled">;

function calcXY(
  pos: FixedPos,
  iW: number, iH: number,
  lW: number, lH: number,
  pad: number,
): [number, number] {
  const map: Record<FixedPos, [number, number]> = {
    "top-left":      [pad,               pad],
    "top-center":    [(iW - lW) / 2,     pad],
    "top-right":     [iW - lW - pad,     pad],
    "middle-left":   [pad,               (iH - lH) / 2],
    "center":        [(iW - lW) / 2,     (iH - lH) / 2],
    "middle-right":  [iW - lW - pad,     (iH - lH) / 2],
    "bottom-left":   [pad,               iH - lH - pad],
    "bottom-center": [(iW - lW) / 2,     iH - lH - pad],
    "bottom-right":  [iW - lW - pad,     iH - lH - pad],
  };
  return map[pos];
}

async function applyWatermark(
  sourceUrl: string,
  logo: HTMLImageElement,
  prefs: WatermarkPrefs,
): Promise<Blob> {
  const src = await loadImg(sourceUrl);
  const canvas = document.createElement("canvas");
  canvas.width = src.naturalWidth;
  canvas.height = src.naturalHeight;
  const ctx = canvas.getContext("2d")!;

  // Fill white so JPEG output has no black artifacts on transparent PNGs
  ctx.fillStyle = "#ffffff";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(src, 0, 0);

  const lW = Math.round(src.naturalWidth * (prefs.logoSizePct / 100));
  const lH = Math.round((logo.naturalHeight / logo.naturalWidth) * lW);
  const pad = Math.round(src.naturalWidth * 0.025);

  const logoAlpha = prefs.logoOpacity / 100;

  if (prefs.position === "tiled") {
    const stepX = lW * 2.8;
    const stepY = lH * 2.8;
    ctx.save();
    ctx.globalAlpha = logoAlpha;
    for (let y = -lH; y < src.naturalHeight + lH; y += stepY) {
      for (let x = -lW; x < src.naturalWidth + lW; x += stepX) {
        ctx.drawImage(logo, x, y, lW, lH);
      }
    }
    ctx.restore();
  } else {
    const [x, y] = calcXY(prefs.position as FixedPos, src.naturalWidth, src.naturalHeight, lW, lH, pad);

    if (prefs.bgEnabled) {
      const bp = Math.round(lW * 0.2);
      const bx = x - bp, by = y - bp;
      const bw = lW + bp * 2, bh = lH + bp * 2;
      const r = Math.round(bp * 0.6);
      ctx.beginPath();
      ctx.moveTo(bx + r, by);
      ctx.lineTo(bx + bw - r, by);
      ctx.arcTo(bx + bw, by, bx + bw, by + r, r);
      ctx.lineTo(bx + bw, by + bh - r);
      ctx.arcTo(bx + bw, by + bh, bx + bw - r, by + bh, r);
      ctx.lineTo(bx + r, by + bh);
      ctx.arcTo(bx, by + bh, bx, by + bh - r, r);
      ctx.lineTo(bx, by + r);
      ctx.arcTo(bx, by, bx + r, by, r);
      ctx.closePath();
      ctx.fillStyle = prefs.bgColor === "white"
        ? `rgba(255,255,255,${prefs.bgOpacity / 100})`
        : `rgba(0,0,0,${prefs.bgOpacity / 100})`;
      ctx.fill();
    }

    ctx.save();
    ctx.globalAlpha = logoAlpha;
    ctx.drawImage(logo, x, y, lW, lH);
    ctx.restore();
  }

  return new Promise((resolve, reject) =>
    canvas.toBlob((b) => b ? resolve(b) : reject(new Error("toBlob")), "image/jpeg", 0.92),
  );
}

// ── Component ───────────────────────────────────────────────────────────────

export function WatermarkClient({ logoDataUrl }: { logoDataUrl: string | null }) {
  const [prefs, setPrefs] = useState<WatermarkPrefs>(DEFAULT_PREFS);
  const [files, setFiles] = useState<WFile[]>([]);
  const [previewId, setPreviewId] = useState<string | null>(null);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [previewLoading, setPreviewLoading] = useState(false);
  const [processing, setProcessing] = useState(false);
  const [logoLoaded, setLogoLoaded] = useState(false);

  const logoRef = useRef<HTMLImageElement | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const prevPreviewRef = useRef<string | null>(null);

  // ── Load prefs from localStorage on mount
  useEffect(() => {
    try {
      const raw = localStorage.getItem(PREFS_KEY);
      if (raw) setPrefs({ ...DEFAULT_PREFS, ...JSON.parse(raw) });
    } catch { /* ignore */ }
  }, []);

  // ── Logo: data URL is pre-fetched server-side, just decode into HTMLImageElement
  useEffect(() => {
    if (!logoDataUrl) return;
    const img = new Image();
    img.onload = () => { logoRef.current = img; setLogoLoaded(true); };
    img.src = logoDataUrl;
  }, [logoDataUrl]);

  // ── Live preview (debounced 300 ms)
  // logoLoaded is in deps so the preview fires once the logo Image decodes
  useEffect(() => {
    if (!previewId || !logoRef.current || !logoLoaded) return;
    const wf = files.find((f) => f.id === previewId);
    if (!wf) return;

    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(async () => {
      if (!logoRef.current) return;
      setPreviewLoading(true);
      try {
        const blob = await applyWatermark(wf.originalUrl, logoRef.current, prefs);
        const url = URL.createObjectURL(blob);
        setPreviewUrl((prev) => {
          if (prev && prev !== prevPreviewRef.current) URL.revokeObjectURL(prev);
          prevPreviewRef.current = url;
          return url;
        });
      } catch { /* ignore */ } finally {
        setPreviewLoading(false);
      }
    }, 300);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [previewId, prefs, logoLoaded]);

  function updatePrefs(patch: Partial<WatermarkPrefs>) {
    setPrefs((prev) => {
      const next = { ...prev, ...patch };
      try { localStorage.setItem(PREFS_KEY, JSON.stringify(next)); } catch { /* ignore */ }
      return next;
    });
  }

  function addFiles(incoming: FileList | File[]) {
    const images = Array.from(incoming).filter((f) => f.type.startsWith("image/"));
    if (!images.length) return;
    setFiles((prev) => {
      const added: WFile[] = images.map((f) => ({
        id: `${f.name}-${f.size}-${Date.now()}-${Math.random()}`,
        file: f,
        originalUrl: URL.createObjectURL(f),
        status: "idle",
      }));
      const next = [...prev, ...added];
      if (!previewId && added.length > 0) setPreviewId(added[0].id);
      return next;
    });
  }

  async function processAll() {
    if (!logoRef.current || !files.length) return;
    setProcessing(true);

    // Snapshot logo + prefs so concurrent tasks all use the same values
    const logo = logoRef.current;
    const currentPrefs = prefs;
    const toProcess = files.filter((f) => f.status !== "done");

    // Mark all pending as "processing" in one batch
    setFiles((p) => p.map((x) =>
      toProcess.some((f) => f.id === x.id) ? { ...x, status: "processing" as const } : x,
    ));

    // Process all files in parallel — each gets its own canvas
    await Promise.all(
      toProcess.map(async (wf) => {
        try {
          const blob = await applyWatermark(wf.originalUrl, logo, currentPrefs);
          setFiles((p) => p.map((x) => x.id === wf.id ? { ...x, status: "done" as const, blob } : x));
        } catch {
          setFiles((p) => p.map((x) => x.id === wf.id ? { ...x, status: "error" as const } : x));
        }
      }),
    );

    setProcessing(false);
    toast.success("Tüm görseller işlendi!");
  }

  async function downloadZip() {
    const done = files.filter((f) => f.blob);
    if (!done.length) { toast.error("Önce görselleri işleyin."); return; }
    try {
      const JSZip = (await import("jszip")).default;
      const zip = new JSZip();
      for (const wf of done) {
        if (wf.blob) zip.file(wf.file.name.replace(/\.[^.]+$/, "") + "_wm.jpg", wf.blob);
      }
      const zipBlob = await zip.generateAsync({ type: "blob", compression: "DEFLATE", compressionOptions: { level: 3 } });
      triggerDownload(zipBlob, "watermarked.zip");
    } catch {
      toast.error("ZIP oluşturulamadı.");
    }
  }

  function downloadSingle(wf: WFile) {
    if (!wf.blob) return;
    triggerDownload(wf.blob, wf.file.name.replace(/\.[^.]+$/, "") + "_wm.jpg");
  }

  function triggerDownload(blob: Blob, filename: string) {
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = filename; a.click();
    URL.revokeObjectURL(url);
  }

  function clearAll() {
    files.forEach((wf) => {
      URL.revokeObjectURL(wf.originalUrl);
    });
    if (previewUrl) URL.revokeObjectURL(previewUrl);
    setFiles([]); setPreviewId(null); setPreviewUrl(null);
  }

  const doneCount = files.filter((f) => f.status === "done").length;

  return (
    <div className="flex flex-col gap-6 p-4 md:p-6">
      {/* Header */}
      <div>
        <h1 className="text-xl font-semibold tracking-tight">Fotoğraf Damgala</h1>
        <p className="text-muted-foreground text-sm mt-0.5">Görsellere otomatik logo ekle ve ZIP olarak indir</p>
      </div>

      <div className="flex gap-6 flex-col lg:flex-row items-start">

        {/* ── Settings panel ──────────────────────────────────── */}
        <div className="w-full lg:w-60 shrink-0 space-y-5">

          {/* Logo */}
          <div className="space-y-2">
            <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Logo</p>
            {logoDataUrl && logoLoaded ? (
              <div className="flex items-center gap-3 p-3 rounded-lg border bg-muted/30">
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img src={logoDataUrl} alt="Logo" className="h-10 w-auto max-w-[110px] object-contain" />
                <span className="text-xs text-muted-foreground">Ofis logosu</span>
              </div>
            ) : logoDataUrl ? (
              <div className="flex items-center gap-2 p-3 rounded-lg border text-muted-foreground text-sm">
                <CircleNotch className="size-4 animate-spin shrink-0" />
                <span>Yükleniyor…</span>
              </div>
            ) : (
              <div className="p-3 rounded-lg border border-dashed text-sm text-muted-foreground flex items-start gap-2">
                <WarningCircle className="size-4 mt-0.5 shrink-0 text-amber-500" />
                <span>
                  Logo bulunamadı.{" "}
                  <a href="/settings/workspace" className="text-primary underline">Ayarlardan</a> yükleyin.
                </span>
              </div>
            )}
          </div>

          {/* Position grid */}
          <div className="space-y-2">
            <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Pozisyon</p>
            <div className="grid grid-cols-3 gap-1">
              {GRID.map((row, ri) =>
                row.map((pos, ci) => {
                  const active = prefs.position === pos;
                  return (
                    <button
                      key={`${ri}-${ci}`}
                      type="button"
                      title={POS_LABELS[pos]}
                      onClick={() => updatePrefs({ position: pos })}
                      className={cn(
                        "h-9 rounded-md border transition-colors flex items-center justify-center",
                        active
                          ? "border-primary bg-primary text-primary-foreground"
                          : "border-border bg-muted/40 hover:bg-muted text-muted-foreground",
                      )}
                    >
                      <span className={cn(
                        "size-2 rounded-sm",
                        active ? "bg-primary-foreground" : "bg-current opacity-50",
                      )} />
                    </button>
                  );
                })
              )}
            </div>
            <button
              type="button"
              onClick={() => updatePrefs({ position: "tiled" })}
              className={cn(
                "w-full h-8 rounded-md border text-xs font-medium transition-colors flex items-center justify-center gap-1.5",
                prefs.position === "tiled"
                  ? "border-primary bg-primary text-primary-foreground"
                  : "border-border bg-muted/40 hover:bg-muted text-muted-foreground",
              )}
            >
              <Repeat className="size-3.5" /> Tekrar (Tiled)
            </button>
            <p className="text-xs text-muted-foreground">{POS_LABELS[prefs.position]}</p>
          </div>

          {/* Logo size */}
          <div className="space-y-2">
            <div className="flex items-center justify-between">
              <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Boyut</Label>
              <span className="text-xs tabular-nums text-muted-foreground">%{prefs.logoSizePct}</span>
            </div>
            <input type="range" min={5} max={40} step={1} value={prefs.logoSizePct}
              onChange={(e) => updatePrefs({ logoSizePct: Number(e.target.value) })}
              className="w-full accent-primary" />
          </div>

          {/* Logo opacity — always visible */}
          <div className="space-y-2">
            <div className="flex items-center justify-between">
              <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Logo Opaklığı</Label>
              <span className="text-xs tabular-nums text-muted-foreground">%{prefs.logoOpacity}</span>
            </div>
            <input type="range" min={10} max={100} step={5} value={prefs.logoOpacity}
              onChange={(e) => updatePrefs({ logoOpacity: Number(e.target.value) })}
              className="w-full accent-primary" />
          </div>

          {/* Background — only for fixed positions */}
          {prefs.position !== "tiled" && (
            <div className="space-y-3">
              <div className="flex items-center justify-between">
                <Label className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Arkaplan</Label>
                <Switch
                  checked={prefs.bgEnabled}
                  onCheckedChange={(v) => updatePrefs({ bgEnabled: v })}
                  className="scale-90"
                />
              </div>

              {prefs.bgEnabled && (
                <>
                  <div className="flex gap-1.5">
                    {(["white", "dark"] as const).map((c) => (
                      <button
                        key={c}
                        type="button"
                        onClick={() => updatePrefs({ bgColor: c })}
                        className={cn(
                          "flex-1 h-7 rounded-md border text-xs transition-colors",
                          prefs.bgColor === c
                            ? "border-primary bg-primary/10 text-primary font-medium"
                            : "border-border text-muted-foreground hover:border-foreground/30",
                        )}
                      >
                        {c === "white" ? "Beyaz" : "Koyu"}
                      </button>
                    ))}
                  </div>
                  <div className="space-y-1.5">
                    <div className="flex justify-between">
                      <span className="text-xs text-muted-foreground">Arkaplan Opaklığı</span>
                      <span className="text-xs tabular-nums text-muted-foreground">%{prefs.bgOpacity}</span>
                    </div>
                    <input type="range" min={10} max={60} step={5} value={prefs.bgOpacity}
                      onChange={(e) => updatePrefs({ bgOpacity: Number(e.target.value) })}
                      className="w-full accent-primary" />
                  </div>
                </>
              )}
            </div>
          )}

          <Button
            className="w-full"
            onClick={processAll}
            disabled={!files.length || !logoLoaded || processing}
          >
            {processing
              ? <><CircleNotch className="size-4 mr-2 animate-spin" />İşleniyor…</>
              : files.length
                ? `${files.length} Görseli İşle`
                : "Görsel Yükle"}
          </Button>
        </div>

        {/* ── Upload + preview ────────────────────────────────── */}
        <div className="flex-1 min-w-0 space-y-4">

          {/* Drop zone */}
          <div
            role="button"
            tabIndex={0}
            onDragOver={(e) => e.preventDefault()}
            onDrop={(e) => { e.preventDefault(); addFiles(e.dataTransfer.files); }}
            onClick={() => fileInputRef.current?.click()}
            onKeyDown={(e) => e.key === "Enter" && fileInputRef.current?.click()}
            className="border-2 border-dashed rounded-xl p-8 text-center cursor-pointer hover:border-primary/50 hover:bg-muted/20 transition-colors"
          >
            <Upload className="size-8 mx-auto text-muted-foreground/40 mb-2" />
            <p className="text-sm font-medium">Görselleri sürükle veya tıkla</p>
            <p className="text-xs text-muted-foreground mt-1">JPG, PNG, WebP — çoklu seçim desteklenir</p>
            <input
              ref={fileInputRef}
              type="file"
              accept="image/*"
              multiple
              className="hidden"
              onChange={(e) => e.target.files && addFiles(e.target.files)}
            />
          </div>

          {/* File grid */}
          {files.length > 0 && (
            <div className="space-y-3">
              <div className="flex items-center justify-between">
                <span className="text-sm font-medium">
                  {files.length} görsel
                  {doneCount > 0 && (
                    <span className="text-muted-foreground font-normal ml-1">({doneCount} işlendi)</span>
                  )}
                </span>
                <div className="flex gap-2">
                  {doneCount > 0 && (
                    <Button variant="outline" size="sm" onClick={downloadZip}>
                      <Download className="size-3.5 mr-1.5" />ZIP İndir
                    </Button>
                  )}
                  <Button variant="ghost" size="sm" onClick={clearAll} className="text-muted-foreground">
                    Temizle
                  </Button>
                </div>
              </div>

              <div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 xl:grid-cols-6 gap-2">
                {files.map((wf) => (
                  <div
                    key={wf.id}
                    role="button"
                    tabIndex={0}
                    onClick={() => setPreviewId(wf.id)}
                    onKeyDown={(e) => e.key === "Enter" && setPreviewId(wf.id)}
                    className={cn(
                      "relative aspect-[4/3] rounded-lg overflow-hidden cursor-pointer border-2 transition-all select-none",
                      previewId === wf.id ? "border-primary shadow-md" : "border-transparent hover:border-border",
                    )}
                  >
                    {/* eslint-disable-next-line @next/next/no-img-element */}
                    <img
                      src={wf.originalUrl}
                      alt={wf.file.name}
                      className="w-full h-full object-cover"
                    />
                    {wf.status === "processing" && (
                      <div className="absolute inset-0 bg-black/40 flex items-center justify-center">
                        <CircleNotch className="size-5 text-white animate-spin" />
                      </div>
                    )}
                    {wf.status === "done" && (
                      <CheckCircle weight="fill" className="absolute top-1 right-1 size-4 text-green-400 drop-shadow" />
                    )}
                    {wf.status === "error" && (
                      <XCircle weight="fill" className="absolute top-1 right-1 size-4 text-red-400 drop-shadow" />
                    )}
                    {wf.status === "done" && wf.blob && (
                      <button
                        type="button"
                        onClick={(e) => { e.stopPropagation(); downloadSingle(wf); }}
                        className="absolute bottom-1 right-1 size-6 rounded bg-black/60 hover:bg-black/80 text-white flex items-center justify-center"
                      >
                        <Download className="size-3" />
                      </button>
                    )}
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* Live preview */}
          {previewId && (
            <div className="rounded-xl border overflow-hidden">
              <div className="flex items-center justify-between px-3 py-2 border-b bg-muted/30">
                <span className="text-xs font-medium text-muted-foreground">
                  Önizleme {previewLoading && <CircleNotch className="size-3 inline animate-spin ml-1" />}
                </span>
                {(() => {
                  const wf = files.find((f) => f.id === previewId);
                  return wf?.status === "done" && wf.blob ? (
                    <Button size="sm" variant="ghost" className="h-6 text-xs gap-1" onClick={() => downloadSingle(wf)}>
                      <Download className="size-3" /> İndir
                    </Button>
                  ) : null;
                })()}
              </div>
              <div className="p-3 flex justify-center bg-muted/10 min-h-32">
                {previewUrl ? (
                  // eslint-disable-next-line @next/next/no-img-element
                  <img
                    src={previewUrl}
                    alt="Önizleme"
                    className="max-w-full h-auto rounded max-h-[55vh] object-contain"
                  />
                ) : (
                  <div className="flex items-center justify-center text-muted-foreground text-sm">
                    {logoLoaded ? "Ayarları değiştirince önizleme yüklenir…" : "Logo yükleniyor…"}
                  </div>
                )}
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
