"use client";
import { useEffect, useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import { Loader2, Plus, Trash2, ArrowUp, ArrowDown, Save, RotateCcw, Hash } from "lucide-react";
import { setPartSuffixPatterns } from "@/app/actions/settings";
import { useSettings } from "./SettingsProvider";
import { cn } from "@/lib/utils";

const DEFAULT_PATTERNS = ["-cd{N}", ".part{N}", "_{N}", "_{L}"];

/**
 * Validate a token-grammar pattern. Returns null if valid, or a short
 * error message if not. Mirrors the rules in lib/video/partClassify.ts.
 */
function validateToken(source: string): string | null {
  if (!source.trim()) return "empty";
  let i = 0;
  let captures = 0;
  while (i < source.length) {
    const c = source[i]!;
    if (c === "{") {
      const close = source.indexOf("}", i);
      if (close < 0) return "unclosed {";
      const tok = source.slice(i, close + 1);
      if (tok !== "{N}" && tok !== "{L}") return `unknown token ${tok}`;
      captures++;
      i = close + 1;
    } else {
      i++;
    }
  }
  if (captures === 0) return "needs {N} or {L}";
  if (captures > 1) return "only one {N}/{L} per pattern";
  return null;
}

/**
 * Settings card body for editing the suffix patterns used to classify
 * video parts vs. variants. Uses option A1 (token grammar) from the
 * mockup — each row is a single editable pattern with reorder/delete.
 */
export function PartSuffixPatterns() {
  const { settings } = useSettings();
  const router = useRouter();
  const [draft, setDraft] = useState<string[]>(settings.partSuffixPatterns ?? DEFAULT_PATTERNS);
  const [saving, setSaving] = useState(false);
  const [, startTransition] = useTransition();

  // Keep the editor in sync with server-side updates (e.g. another tab).
  useEffect(() => {
    setDraft(settings.partSuffixPatterns ?? DEFAULT_PATTERNS);
  }, [settings.partSuffixPatterns]);

  const errors = draft.map(validateToken);
  const hasErrors = errors.some((e) => e != null);
  const dirty =
    draft.length !== (settings.partSuffixPatterns ?? []).length ||
    draft.some((v, i) => v !== (settings.partSuffixPatterns ?? [])[i]);

  function update(i: number, value: string) {
    setDraft((cur) => cur.map((v, idx) => (idx === i ? value : v)));
  }
  function remove(i: number) {
    setDraft((cur) => cur.filter((_, idx) => idx !== i));
  }
  function add() {
    setDraft((cur) => [...cur, ""]);
  }
  function move(i: number, dir: -1 | 1) {
    setDraft((cur) => {
      const j = i + dir;
      if (j < 0 || j >= cur.length) return cur;
      const next = cur.slice();
      [next[i], next[j]] = [next[j]!, next[i]!];
      return next;
    });
  }
  function resetDefaults() {
    setDraft(DEFAULT_PATTERNS.slice());
  }

  async function save() {
    if (hasErrors) return;
    setSaving(true);
    try {
      // Strip empties on save (the action also trims, but UX clarity).
      const cleaned = draft.map((s) => s.trim()).filter(Boolean);
      await setPartSuffixPatterns(cleaned);
      startTransition(() => router.refresh());
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="pt-3 border-t border-[var(--color-glass-border)] space-y-3">
      <div className="space-y-1">
        <div className="text-sm font-medium flex items-center gap-1.5">
          <Hash className="w-3.5 h-3.5 text-[var(--color-cyan)]" />
          Part Suffix Patterns
        </div>
        <div className="text-xs text-[var(--color-fg-muted)] max-w-2xl">
          Match the trailing portion of a filename stem to identify
          sequential parts.{" "}
          <span className="font-mono text-[var(--color-cyan)]">{"{N}"}</span>{" "}
          captures digits,{" "}
          <span className="font-mono text-[var(--color-cyan)]">{"{L}"}</span>{" "}
          captures a single letter (A=1, B=2…). All other characters are
          literal. Files in a code group that match nothing become
          <em> variants</em> of the part they share a stem prefix with.
        </div>
      </div>

      <ol className="space-y-1.5">
        {draft.map((p, i) => {
          const err = errors[i];
          return (
            <li key={i} className="flex items-center gap-2">
              <input
                type="text"
                value={p}
                onChange={(e) => update(i, e.target.value)}
                placeholder="-cd{N}"
                className={cn(
                  "flex-1 glass rounded-lg px-3 py-1.5 text-sm font-mono outline-none",
                  err
                    ? "border border-red-500/50 focus:border-red-400"
                    : "focus:border-[var(--color-cyan)]",
                )}
              />
              <button
                type="button"
                onClick={() => move(i, -1)}
                disabled={i === 0}
                title="Move up"
                className="p-1.5 rounded-lg glass glass-hover disabled:opacity-30"
              >
                <ArrowUp className="w-4 h-4" />
              </button>
              <button
                type="button"
                onClick={() => move(i, 1)}
                disabled={i === draft.length - 1}
                title="Move down"
                className="p-1.5 rounded-lg glass glass-hover disabled:opacity-30"
              >
                <ArrowDown className="w-4 h-4" />
              </button>
              <button
                type="button"
                onClick={() => remove(i)}
                title="Remove"
                className="p-1.5 rounded-lg border border-red-500/30 text-red-300 hover:bg-red-500/10"
              >
                <Trash2 className="w-4 h-4" />
              </button>
            </li>
          );
        })}
      </ol>
      {hasErrors && (
        <div className="text-[11px] text-red-300">
          {errors.map((e, i) => (e ? `Line ${i + 1}: ${e}` : null)).filter(Boolean).join(" · ")}
        </div>
      )}

      <div className="flex items-center gap-2">
        <button
          type="button"
          onClick={add}
          className="inline-flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg glass glass-hover"
        >
          <Plus className="w-4 h-4" /> Add Pattern
        </button>
        <button
          type="button"
          onClick={resetDefaults}
          title="Reset to built-in defaults"
          className="inline-flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg glass glass-hover text-[var(--color-fg-muted)]"
        >
          <RotateCcw className="w-4 h-4" /> Reset to Defaults
        </button>
        <button
          type="button"
          onClick={save}
          disabled={!dirty || saving || hasErrors}
          className="ml-auto inline-flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg bg-[var(--color-cyan)] text-black font-medium disabled:opacity-40 disabled:cursor-not-allowed"
        >
          {saving ? <Loader2 className="w-4 h-4 animate-spin" /> : <Save className="w-4 h-4" />}
          Save &amp; Reclassify
        </button>
      </div>
    </div>
  );
}
