"use client";

import * as React from "react";
import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
import { Select } from "@/components/ui/Select";
import {
  FORMAT_OPTIONS,
  type OutputFormatId,
  fileExtension,
} from "@/lib/outputFormats";

const FORMAT_BY_GROUP = FORMAT_OPTIONS.reduce<Map<string, (typeof FORMAT_OPTIONS)[number][]>>(
  (map, f) => {
    if (!map.has(f.group)) map.set(f.group, []);
    map.get(f.group)!.push(f);
    return map;
  },
  new Map()
);

function clampInt(value: string, min: number, max: number) {
  if (!value.trim()) return undefined;
  const n = Number(value);
  if (!Number.isFinite(n)) return undefined;
  const i = Math.round(n);
  return Math.max(min, Math.min(max, i));
}

export function ConverterCard() {
  const [file, setFile] = React.useState<File | null>(null);
  const [previewUrl, setPreviewUrl] = React.useState<string | null>(null);

  const [format, setFormat] = React.useState<OutputFormatId>("webp");
  const [quality, setQuality] = React.useState<string>("80");
  const [width, setWidth] = React.useState<string>("");
  const [height, setHeight] = React.useState<string>("");

  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [lastDownloadName, setLastDownloadName] = React.useState<string | null>(null);

  React.useEffect(() => {
    if (!file) {
      setPreviewUrl(null);
      return;
    }
    const url = URL.createObjectURL(file);
    setPreviewUrl(url);
    return () => URL.revokeObjectURL(url);
  }, [file]);

  const onPickFile: React.ChangeEventHandler<HTMLInputElement> = (e) => {
    setError(null);
    setLastDownloadName(null);
    const picked = e.target.files?.[0] ?? null;
    setFile(picked);
  };

  const onConvert = async () => {
    setError(null);
    setLastDownloadName(null);
    if (!file) {
      setError("Please choose an image first.");
      return;
    }

    const q = clampInt(quality, 1, 100);
    if (quality.trim() && q == null) {
      setError("Quality must be a number between 1 and 100.");
      return;
    }

    const w = clampInt(width, 1, 10000);
    if (width.trim() && w == null) {
      setError("Width must be a valid number.");
      return;
    }
    const h = clampInt(height, 1, 10000);
    if (height.trim() && h == null) {
      setError("Height must be a valid number.");
      return;
    }

    const form = new FormData();
    form.set("file", file);
    form.set("format", format);
    if (q != null) form.set("quality", String(q));
    if (w != null) form.set("width", String(w));
    if (h != null) form.set("height", String(h));

    setBusy(true);
    try {
      const res = await fetch("/api/convert", { method: "POST", body: form });
      if (!res.ok) {
        const msg = await res.text().catch(() => "");
        throw new Error(msg || `Conversion failed (${res.status})`);
      }

      const blob = await res.blob();
      const base =
        file.name
          .replace(/\.[^/.]+$/, "")
          .replace(/[^\w\-(). ]+/g, "_")
          .trim() || "image";
      const downloadName = `${base}.${fileExtension(format)}`;

      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = downloadName;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);

      setLastDownloadName(downloadName);
    } catch (e) {
      setError(e instanceof Error ? e.message : "Something went wrong.");
    } finally {
      setBusy(false);
    }
  };

  const onReset = () => {
    setFile(null);
    setFormat("webp");
    setQuality("80");
    setWidth("");
    setHeight("");
    setError(null);
    setLastDownloadName(null);
  };

  return (
    <section className="relative w-full min-w-0 overflow-hidden rounded-3xl border border-white/55 bg-white/50 p-5 shadow-2xl shadow-indigo-500/20 backdrop-blur-lg sm:p-8">
      <div
        className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-indigo-400/70 to-transparent"
        aria-hidden
      />
      <div className="pointer-events-none absolute -right-24 -top-24 h-56 w-56 rounded-full bg-gradient-to-br from-violet-400/25 to-fuchsia-400/20 blur-3xl" />
      <div className="pointer-events-none absolute -bottom-28 -left-20 h-64 w-64 rounded-full bg-gradient-to-tr from-cyan-400/20 to-indigo-400/15 blur-3xl" />

      <div className="relative grid gap-6 lg:grid-cols-[1.1fr_0.9fr]">
        <div className="space-y-4">
          <div className="flex items-start justify-between gap-4">
            <div>
              <h2 className="font-display text-xl font-bold tracking-tight text-slate-900">Convert an image</h2>
              <p className="mt-1 text-sm leading-relaxed text-slate-600">
                Upload a raster image; pick from {FORMAT_OPTIONS.length} output presets (grouped in the menu).
              </p>
            </div>
            <Button variant="secondary" size="sm" type="button" onClick={onReset} disabled={busy}>
              Reset
            </Button>
          </div>

          <div className="space-y-2">
            <label className="text-sm font-medium text-slate-800">Image</label>
            <Input
              type="file"
              accept="image/*"
              onChange={onPickFile}
              disabled={busy}
            />
            <p className="text-xs text-slate-500">
              Tip: If you set only width or only height, aspect ratio is preserved.
            </p>
          </div>

          <div className="grid gap-3 sm:grid-cols-2">
            <div className="space-y-2">
              <label className="text-sm font-medium text-slate-800">Output format</label>
              <Select
                value={format}
                onChange={(e) => setFormat(e.target.value as OutputFormatId)}
                disabled={busy}
              >
                {[...FORMAT_BY_GROUP.entries()].map(([group, items]) => (
                  <optgroup key={group} label={group}>
                    {items.map((f) => (
                      <option key={f.id} value={f.id} title={"note" in f ? f.note : undefined}>
                        {f.label}
                      </option>
                    ))}
                  </optgroup>
                ))}
              </Select>
            </div>
            <div className="space-y-2">
              <label className="text-sm font-medium text-slate-800">Quality (1–100)</label>
              <Input
                inputMode="numeric"
                placeholder="80"
                value={quality}
                onChange={(e) => setQuality(e.target.value)}
                disabled={busy}
              />
              <p className="text-xs text-slate-500">
                Applies to lossy codecs; GIF adjusts palette depth; TIFF uses JPEG inside TIFF; HEIC/JPEG XL/JPEG 2000 may
                need extra codecs on the server.
              </p>
            </div>
          </div>

          <div className="grid gap-3 sm:grid-cols-2">
            <div className="space-y-2">
              <label className="text-sm font-medium text-slate-800">Resize width (px)</label>
              <Input
                inputMode="numeric"
                placeholder="(optional)"
                value={width}
                onChange={(e) => setWidth(e.target.value)}
                disabled={busy}
              />
            </div>
            <div className="space-y-2">
              <label className="text-sm font-medium text-slate-800">Resize height (px)</label>
              <Input
                inputMode="numeric"
                placeholder="(optional)"
                value={height}
                onChange={(e) => setHeight(e.target.value)}
                disabled={busy}
              />
            </div>
          </div>

          <div className="flex flex-wrap items-center gap-3 pt-2">
            <Button type="button" onClick={onConvert} disabled={busy || !file}>
              {busy ? "Converting…" : "Convert & download"}
            </Button>
            {lastDownloadName ? (
              <span className="text-sm text-slate-600">
                Downloaded <span className="font-medium text-slate-800">{lastDownloadName}</span>
              </span>
            ) : null}
          </div>

          {error ? (
            <div className="rounded-lg border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">
              {error}
            </div>
          ) : null}
        </div>

        <div className="space-y-3">
          <div className="flex items-center justify-between">
            <h3 className="text-sm font-semibold text-slate-900">Preview</h3>
            {file ? (
              <span className="text-xs text-slate-500">
                {(file.size / (1024 * 1024)).toFixed(2)} MB
              </span>
            ) : null}
          </div>

          <div className="relative overflow-hidden rounded-2xl border border-white/60 bg-gradient-to-br from-slate-50/90 via-white/80 to-indigo-50/50 shadow-inner shadow-indigo-500/10">
            <div className="pointer-events-none absolute inset-0 bg-[linear-gradient(rgba(99,102,241,0.06)_1px,transparent_1px),linear-gradient(90deg,rgba(99,102,241,0.06)_1px,transparent_1px)] bg-[size:24px_24px]" />
            <div className="relative aspect-[4/3] w-full">
              {previewUrl ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={previewUrl}
                  alt="Preview"
                  className="h-full w-full object-contain p-4"
                />
              ) : (
                <div className="flex h-full w-full items-center justify-center p-6 text-center">
                  <div className="max-w-xs">
                    <div className="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-2xl border border-white/70 bg-white/80 shadow-md shadow-indigo-500/10 backdrop-blur">
                      <span className="text-lg text-indigo-400">◆</span>
                    </div>
                    <p className="text-sm font-semibold text-slate-800">No image selected</p>
                    <p className="mt-1 text-xs text-slate-500">
                      Choose a file to see a preview here.
                    </p>
                  </div>
                </div>
              )}
            </div>
          </div>

          <div className="rounded-xl border border-white/60 bg-white/60 px-4 py-3 text-xs text-slate-600 backdrop-blur">
            <div className="flex items-center justify-between">
              <span className="font-semibold text-slate-800">Privacy</span>
              <span className="rounded-full bg-emerald-500/15 px-2 py-0.5 font-semibold text-emerald-800">
                In-memory only
              </span>
            </div>
            <p className="mt-2">
              The server converts your upload and immediately returns the result. No files are saved to disk.
            </p>
          </div>
        </div>
      </div>
    </section>
  );
}

