import { createFileRoute, Link } from "@tanstack/react-router";
import { useEffect, useMemo, useState } from "react";
import { toast } from "sonner";
import { Frame, PageIntro } from "@/components/site/shell";
import { Button, Field, Input, TextArea } from "@/components/ui";
import { SignInGate } from "@/lib/auth/gates";
import { bookVisit, getClinicians, getOpenings, getPreferredLocale, getServices, getShell } from "@/lib/clinic/api";
import { addDays, clinicToday, formatDay, formatMoney, formatWhen } from "@/lib/clinic/locale";
import type { ServiceCard } from "@/lib/clinic/types";
import { useI18n } from "@/lib/i18n/context";

type Search = { service?: string };

export const Route = createFileRoute("/book")({
  validateSearch: (search: Record<string, unknown>): Search => ({
    service: typeof search.service === "string" ? search.service : undefined,
  }),
  loader: async () => {
    const locale = await getPreferredLocale();
    const [shell, services, people] = await Promise.all([
      getShell({ data: locale }),
      getServices({ data: locale }),
      getClinicians({ data: locale }),
    ]);
    return { shell, services: services.services, people };
  },
  component: BookPage,
});

function BookPage() {
  const initial = Route.useLoaderData();
  const search = Route.useSearch();
  const { locale, t } = useI18n();
  const [services, setServices] = useState(initial.services);
  const [people, setPeople] = useState(initial.people);
  const [shell, setShell] = useState(initial.shell);
  const [serviceId, setServiceId] = useState(initial.services.find((item) => item.slug === search.service)?.id ?? initial.services[0]?.id ?? "");
  const [staffId, setStaffId] = useState("");
  const [date, setDate] = useState(clinicToday());
  const [start, setStart] = useState("");
  const [slots, setSlots] = useState<{ start: string; label: string }[]>([]);
  const [reason, setReason] = useState<string | null>(null);
  const [step, setStep] = useState(0);
  const [form, setForm] = useState({ name: "", email: "", phone: "", notes: "" });
  const [error, setError] = useState("");
  const [done, setDone] = useState<{ reference: string } | null>(null);
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    let live = true;
    Promise.all([getServices({ data: locale }), getClinicians({ data: locale }), getShell({ data: locale })]).then(([svc, staff, nextShell]) => {
      if (!live) return;
      setServices(svc.services);
      setPeople(staff);
      setShell(nextShell);
    });
    return () => {
      live = false;
    };
  }, [locale]);

  const service = services.find((item) => item.id === serviceId) ?? services[0];
  const staff = useMemo(() => people.filter((person) => service && person.serviceIds.includes(service.id)), [people, service]);
  useEffect(() => {
    if (!staff.some((person) => person.id === staffId)) setStaffId(staff[0]?.id ?? "");
  }, [staff, staffId]);

  const days = Array.from({ length: 21 }, (_, index) => addDays(clinicToday(), index));

  useEffect(() => {
    if (!service || !staffId || !date) return;
    let live = true;
    getOpenings({ data: { serviceId: service.id, staffId, date } }).then((result) => {
      if (!live) return;
      setSlots(result.slots);
      setReason(result.reason);
      setStart((current) => (result.slots.some((slot) => slot.start === current) ? current : ""));
    });
    return () => {
      live = false;
    };
  }, [service, staffId, date]);

  async function confirm() {
    if (!service) return;
    setBusy(true);
    setError("");
    const result = await bookVisit({
      data: { ...form, serviceId: service.id, staffId, start, locale, notes: form.notes },
    }).catch(() => ({ ok: false as const, error: "forbidden" }));
    setBusy(false);
    if (!result.ok) {
      setError(t(`errors.${result.error}`));
      return;
    }
    toast.success(t("common.saved"));
    setDone({ reference: result.reference });
    setStep(6);
  }

  return (
    <Frame shell={shell}>
      <PageIntro kicker={t("book.kicker")} title={t("book.title")} lead={t("book.lead")} image="/clinic/reception.jpg" />
      <div className="mx-auto max-w-3xl px-4 pb-16">
        {done ? (
          <div className="rounded-xl border border-line bg-paper p-6">
            <h2 className="font-display text-4xl text-forest">{t("book.stepDone")}</h2>
            <p className="mt-3 text-muted">{t("book.confirmedLead")}</p>
            <p className="mt-4 font-mono text-lg tabular-nums">{t("book.reference")}: {done.reference}</p>
            <p className="mt-2">{service?.name} · {formatWhen(start, locale)}</p>
            <div className="mt-6 flex gap-3">
              <Link to="/portal"><Button>{t("book.portal")}</Button></Link>
              <Button variant="line" onClick={() => { setDone(null); setStep(0); }}>{t("book.another")}</Button>
            </div>
          </div>
        ) : (
          <div className="grid gap-6">
            <ol className="flex flex-wrap gap-2 text-xs text-muted">
              {[t("book.stepService"), t("book.stepStaff"), t("book.stepDay"), t("book.stepTime"), t("book.stepDetails"), t("book.stepReview")].map((label, index) => (
                <li key={label}><button type="button" className={index === step ? "text-forest" : ""} onClick={() => setStep(index)}>{index + 1}. {label}</button></li>
              ))}
            </ol>
            {step === 0 && (
              <div className="grid gap-3">
                {services.filter((item) => item.bookable).map((item) => (
                  <button key={item.id} type="button" onClick={() => { setServiceId(item.id); setStep(1); }} className={`rounded-xl border p-4 text-start ${item.id === service?.id ? "border-forest bg-paper" : "border-line"}`}>
                    <span className="font-display text-2xl text-forest">{item.name}</span>
                    <span className="mt-1 block text-sm text-muted">{item.durationMin} {t("common.minutes")} · {formatMoney(item.priceCents, locale)}</span>
                  </button>
                ))}
              </div>
            )}
            {step === 1 && (
              <div className="grid gap-3">
                {staff.map((person) => (
                  <button key={person.id} type="button" onClick={() => { setStaffId(person.id); setStep(2); }} className={`rounded-xl border p-4 text-start ${person.id === staffId ? "border-forest bg-paper" : "border-line"}`}>
                    <span className="font-display text-2xl">{person.name}</span>
                    <span className="block text-sm text-muted">{person.title}</span>
                  </button>
                ))}
              </div>
            )}
            {step === 2 && (
              <div className="flex gap-2 overflow-x-auto pb-2">
                {days.map((day) => (
                  <button key={day} type="button" onClick={() => { setDate(day); setStep(3); }} className={`min-w-24 rounded-lg border px-3 py-3 text-sm ${day === date ? "border-forest bg-forest text-ivory" : "border-line"}`}>
                    {formatDay(day, locale)}
                  </button>
                ))}
              </div>
            )}
            {step === 3 && (
              <div>
                {reason === "holiday" ? <p>{t("book.holiday")}</p> : null}
                {reason === "closed" ? <p>{t("book.closed")}</p> : null}
                {reason === "past" ? <p>{t("book.past")}</p> : null}
                {!slots.length && !reason ? <p>{t("book.noSlots")}</p> : null}
                <div className="mt-3 grid grid-cols-3 gap-2 sm:grid-cols-4">
                  {slots.map((slot) => (
                    <button key={slot.start} type="button" onClick={() => { setStart(slot.start); setStep(4); }} className={`h-11 rounded-md border tabular-nums ${slot.start === start ? "border-forest bg-forest text-ivory" : "border-line"}`}>
                      {slot.label}
                    </button>
                  ))}
                </div>
              </div>
            )}
            {step === 4 && (
              <form className="grid gap-4" onSubmit={(event) => { event.preventDefault(); if (!form.name || !form.email) { setError(t("errors.required")); return; } setStep(5); }}>
                <Field label={t("book.name")}><Input value={form.name} onChange={(event) => setForm({ ...form, name: event.target.value })} required /></Field>
                <Field label={t("book.email")}><Input type="email" value={form.email} onChange={(event) => setForm({ ...form, email: event.target.value })} required /></Field>
                <Field label={t("book.phone")}><Input value={form.phone} onChange={(event) => setForm({ ...form, phone: event.target.value })} /></Field>
                <Field label={t("book.notes")} hint={t("book.notesHint")}><TextArea value={form.notes} onChange={(event) => setForm({ ...form, notes: event.target.value })} /></Field>
                {error ? <p className="text-danger">{error}</p> : null}
                <Button type="submit">{t("common.continue")}</Button>
              </form>
            )}
            {step === 5 && service && (
              <div className="rounded-xl border border-line p-5">
                <Review service={service} staffName={staff.find((person) => person.id === staffId)?.name ?? ""} when={start} form={form} />
                <p className="mt-4 text-sm text-muted">{t("book.policy")}</p>
                <p className="text-sm text-muted">{t("common.priceNote")}</p>
                {error ? <p className="mt-3 text-danger">{error}</p> : null}
                <div className="mt-5">
                  <SignInGate fallback={<Link to="/login"><Button>{t("book.signInToConfirm")}</Button></Link>}>
                    <Button disabled={busy || !start} onClick={() => void confirm()}>{busy ? t("common.saving") : t("common.confirm")}</Button>
                  </SignInGate>
                </div>
              </div>
            )}
            {step > 0 && step < 5 ? <Button variant="ghost" onClick={() => setStep((value) => value - 1)}>{t("common.back")}</Button> : null}
          </div>
        )}
      </div>
    </Frame>
  );
}

function Review({ service, staffName, when, form }: { service: ServiceCard; staffName: string; when: string; form: { name: string; email: string; phone: string; notes: string } }) {
  const { locale, t } = useI18n();
  return (
    <dl className="grid gap-2 text-sm">
      <div className="flex justify-between gap-4"><dt>{t("book.stepService")}</dt><dd>{service.name}</dd></div>
      <div className="flex justify-between gap-4"><dt>{t("book.stepStaff")}</dt><dd>{staffName}</dd></div>
      <div className="flex justify-between gap-4"><dt>{t("book.stepTime")}</dt><dd>{when ? formatWhen(when, locale) : "—"}</dd></div>
      <div className="flex justify-between gap-4"><dt>{t("services.price")}</dt><dd className="tabular-nums">{formatMoney(service.priceCents, locale)}</dd></div>
      <div className="flex justify-between gap-4"><dt>{t("book.name")}</dt><dd>{form.name}</dd></div>
      <div className="flex justify-between gap-4"><dt>{t("book.email")}</dt><dd>{form.email}</dd></div>
    </dl>
  );
}
