"use client";

import { useState, useTransition, type ReactNode } from "react";
import { Button } from "@/components/ui";
import { inputClass } from "@/components/ui/form";
import { saveSiteSectionAction } from "@/lib/actions/site-admin";
import { cn } from "@/lib/utils";

export type SectionMsg = { ok: boolean; text: string } | null;

/** Saves one section of the site settings; `errors` are keyed by the field path the server reports. */
export function useSection(siteId: string) {
  const [pending, start] = useTransition();
  const [msg, setMsg] = useState<SectionMsg>(null);
  const [errors, setErrors] = useState<Record<string, string>>({});
  const save = (section: string, value: unknown, onOk?: () => void) => {
    setMsg(null); setErrors({});
    start(async () => {
      const r = await saveSiteSectionAction(siteId, { section, value });
      if (r.ok) { setMsg({ ok: true, text: "Saved" }); onOk?.(); }
      else { setErrors(Object.fromEntries(Object.entries(r.fieldErrors ?? {}).map(([k, v]) => [k.replace(/^value\./, ""), v]))); setMsg({ ok: false, text: r.error }); }
    });
  };
  return { pending, msg, errors, save };
}

export function SaveBar({ pending, msg, onSave, label = "Save changes" }: { pending: boolean; msg: SectionMsg; onSave: () => void; label?: string }) {
  return (
    <div className="flex items-center gap-3">
      <Button onClick={onSave} disabled={pending}>{pending ? "Saving…" : label}</Button>
      <p role="status" aria-live="polite" className={msg ? (msg.ok ? "text-sm text-success" : "text-sm text-danger") : "sr-only"}>{msg?.text}</p>
    </div>
  );
}

/** Tab strip that switches panels in place (no navigation). */
const slug = (v: string) => v.toLowerCase().replace(/[^a-z0-9]+/g, "-");

export function SubTabs<T extends string>({ label, tabs, value, onChange }: { label: string; tabs: readonly { id: T; label: string }[]; value: T; onChange: (v: T) => void }) {
  return (
    <div role="tablist" aria-label={label} className="mb-4 flex flex-wrap gap-1 border-b border-border">
      {tabs.map((t) => (
        <button key={t.id} type="button" role="tab" id={`tab-${slug(label)}-${t.id}`} aria-selected={value === t.id} aria-controls={`panel-${slug(label)}`} onClick={() => onChange(t.id)}
          className={cn("-mb-px border-b-2 px-3 py-2 text-sm", value === t.id ? "border-primary font-medium" : "border-transparent text-muted-foreground hover:text-foreground")}>{t.label}</button>
      ))}
    </div>
  );
}

export function Panel({ label, tab, children }: { label: string; tab: string; children: ReactNode }) {
  return <div role="tabpanel" id={`panel-${slug(label)}`} aria-labelledby={`tab-${slug(label)}-${tab}`} className="space-y-4">{children}</div>;
}

export function Check({ id, label, checked, onChange, help }: { id: string; label: string; checked: boolean; onChange: (v: boolean) => void; help?: string }) {
  return (
    <div className="space-y-1">
      <label className="flex items-center gap-2 text-sm"><input id={id} type="checkbox" checked={checked} onChange={(e) => onChange(e.target.checked)} aria-describedby={help ? `${id}-help` : undefined} />{label}</label>
      {help ? <p id={`${id}-help`} className="text-xs text-muted-foreground">{help}</p> : null}
    </div>
  );
}

const HEX = /^#[0-9a-fA-F]{6}$/;
/** Colour swatch + hex text box (the text box is the accessible, keyboard-friendly way to set an exact value). */
export function Colour({ id, label, value, onChange, error }: { id: string; label: string; value: string; onChange: (v: string) => void; error?: string }) {
  return (
    <div className="space-y-1">
      <label htmlFor={id} className="block text-xs font-medium">{label}</label>
      <div className="flex items-center gap-2">
        <input type="color" aria-label={`${label} picker`} value={HEX.test(value) ? value : "#000000"} onChange={(e) => onChange(e.target.value)} className="h-9 w-10 shrink-0 cursor-pointer rounded-md border border-border bg-card p-1" />
        <input id={id} className={inputClass} value={value} maxLength={7} onChange={(e) => onChange(e.target.value)} aria-invalid={error ? true : undefined} />
      </div>
      {error ? <p role="alert" className="text-xs text-danger">{error}</p> : null}
    </div>
  );
}

export function Select<T extends string>({ id, value, onChange, options, className }: { id: string; value: T; onChange: (v: T) => void; options: readonly { value: T; label: string }[]; className?: string }) {
  return (
    <select id={id} className={cn(inputClass, className)} value={value} onChange={(e) => onChange(e.target.value as T)}>
      {options.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
    </select>
  );
}
