"use client";

import { useState } from "react";
import {
  matchBatchFilenames,
  submitBatchUpload,
  type BatchMatchResult,
  type BatchResolution,
  type BatchUploadResult,
} from "@/lib/actions/batch-upload";
import {
  centerSquareCropRect,
  cropToCircularPng,
  loadImageFromFile,
} from "@/lib/image-crop";

type Row = BatchMatchResult & {
  confirmedNew: boolean;
  file: File;
};

const STATUS_LABELS: Record<BatchMatchResult["status"], string> = {
  matched: "Matched",
  new_blend: "New blend",
  new_brand: "New brand and blend",
  blocked: "Blocked",
  unparseable: "Couldn't read filename",
};

const STATUS_STYLES: Record<BatchMatchResult["status"], string> = {
  matched: "bg-green-100 text-green-800",
  new_blend: "bg-gold/20 text-charcoal",
  new_brand: "bg-gold/20 text-charcoal",
  blocked: "bg-terracotta/10 text-terracotta",
  unparseable: "bg-charcoal/10 text-charcoal/60",
};

// Batch upload has no interactive crop step, so each file gets an
// algorithmic center + cover-fit circular crop instead -- same transparent
// circular PNG output as the interactive tool, just without letting the
// user reposition it first. Falls back to the original file if cropping
// fails (e.g. a corrupt image); server-side validation still rejects it
// with the same message it always has.
async function cropFileToCircularPng(file: File): Promise<File> {
  try {
    const img = await loadImageFromFile(file);
    const rect = centerSquareCropRect(img.width, img.height);
    const blob = await cropToCircularPng(img, rect);
    const name = file.name.replace(/\.\w+$/, ".png");
    return new File([blob], name, { type: "image/png" });
  } catch {
    return file;
  }
}

export function BatchUploadForm() {
  const [rows, setRows] = useState<Row[] | null>(null);
  const [isMatching, setIsMatching] = useState(false);
  const [isUploading, setIsUploading] = useState(false);
  const [results, setResults] = useState<BatchUploadResult[] | null>(null);

  async function handleFilesSelected(e: React.ChangeEvent<HTMLInputElement>) {
    const files = Array.from(e.target.files ?? []);
    if (files.length === 0) return;

    setResults(null);
    setIsMatching(true);

    const [matches, croppedFiles] = await Promise.all([
      matchBatchFilenames(files.map((f) => f.name)),
      Promise.all(files.map(cropFileToCircularPng)),
    ]);
    const croppedMap = new Map(files.map((f, i) => [f.name, croppedFiles[i]]));

    setRows(
      matches.map((m) => ({
        ...m,
        confirmedNew: false,
        file: croppedMap.get(m.fileName)!,
      })),
    );
    setIsMatching(false);
  }

  function toggleConfirm(fileName: string) {
    setRows((prev) =>
      prev
        ? prev.map((r) =>
            r.fileName === fileName
              ? { ...r, confirmedNew: !r.confirmedNew }
              : r,
          )
        : prev,
    );
  }

  const includedRows = (rows ?? []).filter(
    (r) =>
      r.status === "matched" ||
      ((r.status === "new_blend" || r.status === "new_brand") &&
        r.confirmedNew),
  );

  async function handleUpload() {
    if (includedRows.length === 0) return;
    setIsUploading(true);

    const resolutions: BatchResolution[] = includedRows.map((r) =>
      r.status === "matched"
        ? { fileName: r.fileName, action: "use_existing", blendId: r.blendId! }
        : {
            fileName: r.fileName,
            action: "create_new",
            brandName: r.brandInput,
            blendName: r.blendInput,
          },
    );

    const formData = new FormData();
    formData.set("resolutions", JSON.stringify(resolutions));
    for (const row of includedRows) {
      formData.set(`file:${row.fileName}`, row.file);
    }

    const outcome = await submitBatchUpload(formData);
    setResults(outcome);
    setIsUploading(false);
  }

  return (
    <div className="flex flex-col gap-6">
      <label className="flex flex-col gap-1">
        <span className="text-sm font-medium text-charcoal">
          Label images
        </span>
        <input
          type="file"
          accept="image/png,image/jpeg"
          multiple
          onChange={handleFilesSelected}
          className="rounded border border-charcoal/20 bg-warm-white px-4 py-2 text-charcoal"
        />
      </label>

      {isMatching && (
        <p className="text-sm text-charcoal/60">Matching filenames...</p>
      )}

      {rows && rows.length > 0 && (
        <div className="flex flex-col gap-3">
          {rows.map((row) => (
            <div
              key={row.fileName}
              className="flex flex-col gap-2 rounded-lg border border-charcoal/10 bg-warm-white p-4 sm:flex-row sm:items-center sm:justify-between"
            >
              <div>
                <p className="font-medium text-charcoal">{row.fileName}</p>
                {row.status !== "unparseable" && (
                  <p className="text-sm text-charcoal/60">
                    {row.brandInput} &middot; {row.blendInput}
                  </p>
                )}
                {row.status === "blocked" && row.blockedNote && (
                  <p className="text-sm text-terracotta">{row.blockedNote}</p>
                )}
                {row.status === "unparseable" && (
                  <p className="text-sm text-terracotta">
                    Rename to &ldquo;Brand - Blend.{row.fileName.split(".").pop()}&rdquo;
                  </p>
                )}
              </div>

              <div className="flex items-center gap-3">
                <span
                  className={`rounded-full px-3 py-1 text-xs font-medium ${STATUS_STYLES[row.status]}`}
                >
                  {STATUS_LABELS[row.status]}
                </span>
                {(row.status === "new_blend" || row.status === "new_brand") && (
                  <label className="flex items-center gap-2 text-sm text-charcoal">
                    <input
                      type="checkbox"
                      checked={row.confirmedNew}
                      onChange={() => toggleConfirm(row.fileName)}
                    />
                    Add to catalog
                  </label>
                )}
              </div>
            </div>
          ))}

          <button
            type="button"
            onClick={handleUpload}
            disabled={isUploading || includedRows.length === 0}
            className="w-fit rounded-full bg-terracotta px-6 py-2 font-medium text-white hover:bg-terracotta/90 disabled:opacity-60"
          >
            {isUploading
              ? "Uploading..."
              : `Upload ${includedRows.length} label${includedRows.length === 1 ? "" : "s"}`}
          </button>
        </div>
      )}

      {results && (
        <div className="flex flex-col gap-2 rounded-lg border border-charcoal/10 bg-warm-white p-4">
          <p className="font-medium text-charcoal">
            {results.filter((r) => r.success).length} of {results.length}{" "}
            uploaded successfully
          </p>
          {results.map((r) => (
            <p
              key={r.fileName}
              className={`text-sm ${r.success ? "text-charcoal/60" : "text-terracotta"}`}
            >
              {r.fileName}: {r.success ? "Uploaded" : r.error}
            </p>
          ))}
        </div>
      )}
    </div>
  );
}
