"use client";

import { useCallback, useEffect, useState, type FormEvent } from "react";
import { ListChecks, Plus } from "lucide-react";
import { Button, ConfirmDialog, Dialog, EmptyState, Field, Input, PageHeader, Panel, Select, Skeleton } from "@/components/ui/kit";
import { useToast } from "@/components/ui/toast";
import { useSession } from "@/components/session";
import { api, ApiError } from "@/lib/api";
import type { CustomField } from "@/lib/types";

const TYPE_LABELS = { text: "Text", number: "Number", date: "Date", email: "Email" } as const;

export default function CustomFieldsPage() {
  const { can } = useSession();
  const toast = useToast();
  const [fields, setFields] = useState<CustomField[] | null>(null);
  const [editing, setEditing] = useState<CustomField | "new" | null>(null);
  const [toDelete, setToDelete] = useState<CustomField | null>(null);
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [saving, setSaving] = useState(false);

  const load = useCallback(() => api.get<{ data: CustomField[] }>("/custom-fields").then((r) => setFields(r.data)), []);
  useEffect(() => {
    load().catch((e) => toast("error", e.message));
  }, [load, toast]);

  const current = editing && editing !== "new" ? editing : null;

  async function save(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const body = Object.fromEntries(new FormData(e.currentTarget)) as Record<string, string>;
    if (!body.key) delete body.key;
    setSaving(true);
    setErrors({});
    try {
      if (current) await api.patch(`/custom-fields/${current.id}`, { label: body.label, type: body.type });
      else await api.post("/custom-fields", body);
      toast("success", current ? "Field saved" : "Field added");
      setEditing(null);
      load();
    } catch (err) {
      if (err instanceof ApiError && Object.keys(err.fields).length) setErrors(err.fields);
      else toast("error", (err as Error).message);
    } finally {
      setSaving(false);
    }
  }

  async function remove() {
    if (!toDelete) return;
    setSaving(true);
    try {
      await api.delete(`/custom-fields/${toDelete.id}`);
      toast("success", "Field deleted");
      setToDelete(null);
      load();
    } catch (e) {
      toast("error", (e as Error).message);
    } finally {
      setSaving(false);
    }
  }

  return (
    <>
      <PageHeader
        title="Custom fields"
        description="Extra details you keep for each contact, like city or birthday. Use them in messages as {key}, and as columns when importing."
        actions={
          can("custom_fields.manage") && (
            <Button variant="primary" icon={<Plus className="size-4" />} onClick={() => { setErrors({}); setEditing("new"); }}>
              New field
            </Button>
          )
        }
      />
      <Panel>
        {!fields ? (
          <div className="space-y-3 p-4">
            <Skeleton className="h-6 w-full" />
            <Skeleton className="h-6 w-full" />
          </div>
        ) : fields.length === 0 ? (
          <EmptyState icon={<ListChecks className="size-5" />} title="No custom fields yet" body="Built-in fields cover name, number, email, country and language. Add your own for anything else." />
        ) : (
          <div className="relative overflow-x-auto">
          <table className="w-full min-w-[560px] text-sm">
            <thead>
              <tr className="border-b border-line text-left text-[13px] text-muted">
                <th className="px-4 py-2.5 font-medium">Label</th>
                <th className="px-4 py-2.5 font-medium">Variable</th>
                <th className="px-4 py-2.5 font-medium">Type</th>
                <th className="px-4 py-2.5">
                  <span className="sr-only">Actions</span>
                </th>
              </tr>
            </thead>
            <tbody>
              {fields.map((f) => (
                <tr key={f.id} className="border-b border-line last:border-0 hover:bg-paper/70">
                  <td className="px-4 py-3 font-medium text-ink">{f.label}</td>
                  <td className="px-4 py-3">
                    <code className="rounded bg-paper px-1.5 py-0.5 text-[13px] text-teal">{`{${f.key}}`}</code>
                  </td>
                  <td className="px-4 py-3 text-muted">{TYPE_LABELS[f.type]}</td>
                  <td className="whitespace-nowrap px-4 py-3 text-right">
                    {can("custom_fields.manage") && (
                      <>
                        <Button size="sm" variant="ghost" onClick={() => { setErrors({}); setEditing(f); }}>
                          Edit
                        </Button>
                        <Button size="sm" variant="ghost" className="hover:bg-brick-soft hover:text-brick" onClick={() => setToDelete(f)}>
                          Delete
                        </Button>
                      </>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
          </div>
        )}
      </Panel>

      <Dialog
        open={editing !== null}
        onClose={() => setEditing(null)}
        title={current ? "Edit field" : "New field"}
        size="sm"
        footer={
          <>
            <Button onClick={() => setEditing(null)}>Cancel</Button>
            <Button variant="primary" type="submit" form="cf-form" loading={saving}>
              {current ? "Save field" : "Add field"}
            </Button>
          </>
        }
      >
        <form id="cf-form" onSubmit={save} className="space-y-4" noValidate>
          <Field label="Label" htmlFor="f-label" error={errors.label}>
            <Input id="f-label" name="label" defaultValue={current?.label ?? ""} invalid={!!errors.label} autoFocus />
          </Field>
          {current ? (
            <Field label="Variable" hint="The variable can't change after creation, because messages and import files refer to it.">
              <code className="rounded bg-paper px-2 py-1.5 text-sm text-teal">{`{${current.key}}`}</code>
            </Field>
          ) : (
            <Field label="Variable key" htmlFor="f-key" optional error={errors.key} hint="Lowercase letters, numbers and underscores. Leave blank to create it from the label.">
              <Input id="f-key" name="key" placeholder="e.g. city" invalid={!!errors.key} />
            </Field>
          )}
          <Field label="Type" htmlFor="f-type">
            <Select id="f-type" name="type" defaultValue={current?.type ?? "text"}>
              {Object.entries(TYPE_LABELS).map(([v, l]) => (
                <option key={v} value={v}>
                  {l}
                </option>
              ))}
            </Select>
          </Field>
        </form>
      </Dialog>

      <ConfirmDialog
        open={!!toDelete}
        title={`Delete "${toDelete?.label}"?`}
        message="The value stored for every contact will be removed too. Messages that use this variable will show it blank."
        confirmLabel="Delete field"
        loading={saving}
        onConfirm={remove}
        onClose={() => setToDelete(null)}
      />
    </>
  );
}
