"use client";

import { useState } from "react";
import { Plus, Trash2, ArrowUp, ArrowDown } from "lucide-react";
import { clsx } from "clsx";
import { FieldShell, InputField, TextareaField } from "./FormField";

export type RepeaterFieldDef = {
  key: string;
  label: string;
  type?: "text" | "textarea" | "select";
  placeholder?: string;
  required?: boolean;
  options?: Array<{ value: string; label: string }>;
  rows?: number;
  /** Grid column span (1, 2 or 3 – on md+ screens). Defaults to full row. */
  span?: 1 | 2 | 3;
  maxLength?: number;
};

type Props<T extends Record<string, string>> = {
  /** Form field name that the server action will receive as a JSON string. */
  name: string;
  /** Human-readable label for the group. */
  label: string;
  /** Explainer under the label. */
  hint?: string;
  /** Shape description for each row. */
  fields: RepeaterFieldDef[];
  /** Initial items. */
  defaultValue: T[];
  /** Label for the "add new row" button. */
  addLabel?: string;
  /** Template row used when the user clicks "Add item". Must be a plain object
   * because this component is "use client" and server→client boundaries don't
   * allow function props. */
  emptyRow: T;
  /** Max number of rows enforced client-side. */
  max?: number;
};

/**
 * Controlled repeater that renders a list of rows with add/remove/reorder
 * controls. On submit the full list is serialised as a JSON string into a
 * single hidden input so the server action can `JSON.parse()` it.
 */
export function RepeaterField<T extends Record<string, string>>({
  name,
  label,
  hint,
  fields,
  defaultValue,
  addLabel = "Add item",
  emptyRow,
  max,
}: Props<T>) {
  const [items, setItems] = useState<T[]>(defaultValue);
  const [announce, setAnnounce] = useState<string>("");

  const updateItem = (index: number, key: string, value: string) => {
    setItems((prev) => {
      const next = [...prev];
      next[index] = { ...next[index], [key]: value };
      return next;
    });
  };

  const remove = (index: number) => {
    setItems((prev) => prev.filter((_, i) => i !== index));
    setAnnounce(`Removed item ${index + 1}. ${items.length - 1} remaining.`);
  };

  const add = () => {
    if (max && items.length >= max) return;
    setItems((prev) => [...prev, { ...emptyRow }]);
    setAnnounce(`Added item ${items.length + 1}.`);
  };

  const move = (index: number, dir: -1 | 1) => {
    const target = index + dir;
    if (target < 0 || target >= items.length) return;
    setItems((prev) => {
      const next = [...prev];
      const [row] = next.splice(index, 1);
      next.splice(target, 0, row);
      return next;
    });
    setAnnounce(
      `Moved item ${index + 1} ${dir === -1 ? "up" : "down"} to position ${target + 1}.`,
    );
  };

  return (
    <FieldShell label={label} hint={hint}>
      <input type="hidden" name={name} value={JSON.stringify(items)} />
      <span className="sr-only" aria-live="polite" aria-atomic="true">
        {announce}
      </span>
      <div className="flex flex-col gap-3">
        {items.length === 0 ? (
          <p className="rounded-lg border border-dashed border-[var(--color-line)] bg-[var(--color-mist)]/40 px-4 py-6 text-center text-[13px] text-[var(--color-slate)]">
            No items yet. Use <strong>{addLabel}</strong> below to add one.
          </p>
        ) : null}
        {items.map((row, i) => (
          <div
            key={i}
            className="rounded-xl border border-[var(--color-line)] bg-white p-4"
          >
            <div className="mb-3 flex items-center justify-between gap-3">
              <span className="text-[11px] font-bold uppercase tracking-wider text-[var(--color-slate)]">
                Item {i + 1}
              </span>
              <div className="flex items-center gap-1">
                <button
                  type="button"
                  onClick={() => move(i, -1)}
                  disabled={i === 0}
                  aria-label="Move up"
                  className="inline-flex h-7 w-7 items-center justify-center rounded-md border border-[var(--color-line)] text-[var(--color-slate)] transition-colors hover:border-[var(--color-blue)] hover:text-[var(--color-blue)] disabled:opacity-40"
                >
                  <ArrowUp className="h-3.5 w-3.5" aria-hidden />
                </button>
                <button
                  type="button"
                  onClick={() => move(i, 1)}
                  disabled={i === items.length - 1}
                  aria-label="Move down"
                  className="inline-flex h-7 w-7 items-center justify-center rounded-md border border-[var(--color-line)] text-[var(--color-slate)] transition-colors hover:border-[var(--color-blue)] hover:text-[var(--color-blue)] disabled:opacity-40"
                >
                  <ArrowDown className="h-3.5 w-3.5" aria-hidden />
                </button>
                <button
                  type="button"
                  onClick={() => remove(i)}
                  aria-label="Delete"
                  className="inline-flex h-7 w-7 items-center justify-center rounded-md border border-red-200 text-red-600 transition-colors hover:border-red-400 hover:bg-red-50"
                >
                  <Trash2 className="h-3.5 w-3.5" aria-hidden />
                </button>
              </div>
            </div>
            <div className="grid gap-3 md:grid-cols-3">
              {fields.map((f) => {
                const value = (row[f.key] as string | undefined) ?? "";
                const onChange = (v: string) => updateItem(i, f.key, v);
                const spanClass = clsx(
                  f.span === 1 && "md:col-span-1",
                  f.span === 2 && "md:col-span-2",
                  (!f.span || f.span === 3) && "md:col-span-3",
                );
                if (f.type === "textarea") {
                  return (
                    <TextareaField
                      key={f.key}
                      label={f.label}
                      value={value}
                      onChange={(e) => onChange(e.target.value)}
                      rows={f.rows ?? 3}
                      placeholder={f.placeholder}
                      wrapClassName={spanClass}
                      maxLength={f.maxLength}
                    />
                  );
                }
                if (f.type === "select" && f.options) {
                  return (
                    <FieldShell
                      key={f.key}
                      label={f.label}
                      className={spanClass}
                    >
                      <select
                        value={value}
                        onChange={(e) => onChange(e.target.value)}
                        className="w-full rounded-md border border-[var(--color-line)] bg-white px-3 py-2 text-[14px] text-[var(--color-ink)] shadow-[inset_0_1px_0_rgba(10,15,46,0.02)] focus:border-[var(--color-blue)] focus:outline-none focus:ring-2 focus:ring-[var(--color-mist)]"
                      >
                        <option value="">—</option>
                        {f.options.map((o) => (
                          <option key={o.value} value={o.value}>
                            {o.label}
                          </option>
                        ))}
                      </select>
                    </FieldShell>
                  );
                }
                return (
                  <InputField
                    key={f.key}
                    label={f.label}
                    value={value}
                    onChange={(e) => onChange(e.target.value)}
                    placeholder={f.placeholder}
                    wrapClassName={spanClass}
                    maxLength={f.maxLength}
                  />
                );
              })}
            </div>
          </div>
        ))}
      </div>
      <button
        type="button"
        onClick={add}
        disabled={max ? items.length >= max : false}
        className="mt-3 inline-flex items-center gap-1.5 self-start rounded-lg border border-[var(--color-line)] bg-white px-3 py-2 text-[13px] font-semibold text-[var(--color-ink)] transition-colors hover:border-[var(--color-blue)] hover:text-[var(--color-blue)] disabled:opacity-50"
      >
        <Plus className="h-3.5 w-3.5" aria-hidden />
        {addLabel}
        {max ? ` (${items.length} / ${max})` : null}
      </button>
    </FieldShell>
  );
}
