"use client";

/**
 * The prescription form (PRD 4.4, CU-06) on the Medora design system: used by Prescriptions to add and edit, and by
 * the till to write one from a sale it has just completed (`fromSale`: its customer and lines filled in, and the
 * sale linked). It replaces the till's old "Generate prescription" form, the last screen on the old styles.
 */

import * as React from "react";
import { PlusIcon, XIcon } from "lucide-react";

import { RecordDrawer } from "@/components/medora/drawer";
import { Button } from "@/components/ui/button";
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Spinner } from "@/components/ui/spinner";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
import { toast } from "@/components/ui/toast";
import { CustomersApi, PrescriptionsApi, ProductsApi } from "@/lib/api";
import { formatPhone, localToday } from "@/lib/format";

export type RxItem = { productId?: number | null; productName: string; dosage?: string | null; frequency?: string | null; quantity: number };
export type Rx = { id: number; patientName: string; patientId?: string | null; prescriber?: string | null; dateIssued: string; status: string; hasAlert: boolean; notes?: string | null; customerId?: number | null; items?: RxItem[] };

/** A completed sale at the till, to write its prescription from. */
export type RxFromSale = { saleId?: number; receiptId: string; customer?: { id?: number; name: string } | null; items: { id: number; name: string; qty: number }[] };

const FREQUENCIES = ["Once daily", "Twice daily", "Three times daily", "Every 8 hours", "Every 6 hours", "Every 12 hours", "As needed (PRN)", "With food", "At bedtime"];
export const apiError = (e: unknown, fallback: string): string => {
  const m = (e as { response?: { data?: { message?: string | string[] } } })?.response?.data?.message;
  return Array.isArray(m) ? m.join(" ") : m || fallback;
};
export const ref = (id: number) => `RX-${String(id).padStart(5, "0")}`;

export function PrescriptionForm({ rx, fromSale, onClose, onSaved }: { rx: Rx | null; fromSale?: RxFromSale; onClose: () => void; onSaved: () => void }) {
  const me = React.useMemo(() => {
    try {
      return JSON.parse(localStorage.getItem("user") || "{}") as { name?: string; username?: string };
    } catch {
      return {};
    }
  }, []);
  const start = React.useMemo(
    () => ({
      customer: rx?.customerId
        ? { id: rx.customerId, name: rx.patientName }
        : fromSale?.customer?.id
          ? { id: fromSale.customer.id, name: fromSale.customer.name }
          : (null as { id: number; name: string } | null),
      patientName: rx?.patientName ?? fromSale?.customer?.name ?? "",
      patientId: rx?.patientId ?? "",
      prescriber: rx?.prescriber ?? me.name ?? me.username ?? "",
      dateIssued: rx?.dateIssued?.slice(0, 10) ?? localToday(),
      hasAlert: rx?.hasAlert ?? false,
      notes: rx?.notes ?? "",
      items: rx?.items?.length
        ? rx.items.map((i) => ({ ...i, dosage: i.dosage ?? "", frequency: i.frequency ?? "" }))
        : fromSale?.items.length
          ? fromSale.items.map((i) => ({ productId: i.id as number | null, productName: i.name, dosage: "", frequency: "", quantity: i.qty }))
          : [{ productName: "", dosage: "", frequency: "", quantity: 1 }],
    }),
    [rx, fromSale, me],
  );
  const [f, setF] = React.useState(start);
  const [tried, setTried] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const [patients, setPatients] = React.useState<{ id: number; name: string; phone?: string }[]>([]);
  const [products, setProducts] = React.useState<{ id: number; name: string }[]>([]);

  // Find a registered customer as the patient, and products for the lines
  React.useEffect(() => {
    const term = f.patientName.trim();
    if (f.customer || term.length < 2) return setPatients([]);
    const t = setTimeout(() => {
      CustomersApi.list({ search: term, pageSize: 6 })
        .then((r) => setPatients(r.rows.map((c) => ({ id: c.id, name: c.name, phone: c.phone || undefined }))))
        .catch(() => setPatients([]));
    }, 250);
    return () => clearTimeout(t);
  }, [f.patientName, f.customer]);
  React.useEffect(() => {
    ProductsApi.getAll()
      .then((ps: { id: number; name: string }[]) => setProducts(ps.map((p) => ({ id: p.id, name: p.name }))))
      .catch(() => setProducts([]));
  }, []);

  const lines = f.items.filter((i) => i.productName.trim());
  const problems = {
    // From a sale, a blank patient is a walk-in, as the till's form has always allowed
    patient: f.patientName.trim() || fromSale ? undefined : "Choose the patient or type their name.",
    items: lines.length ? undefined : "Add at least one medicine.",
    date: f.dateIssued ? undefined : "Enter the date it was written.",
  };
  const setItem = (k: number, patch: Partial<{ productId: number | null; productName: string; dosage: string; frequency: string; quantity: number }>) => setF((x) => ({ ...x, items: x.items.map((it, i) => (i === k ? { ...it, ...patch } : it)) }));

  const save = async () => {
    setTried(true);
    if (Object.values(problems).some(Boolean)) return;
    setSaving(true);
    const payload = {
      patientName: f.patientName.trim() || "Walk-in patient",
      patientId: f.patientId.trim() || undefined,
      prescriber: f.prescriber.trim() || undefined,
      dateIssued: f.dateIssued,
      hasAlert: f.hasAlert,
      notes: f.notes.trim() || undefined,
      customerId: f.customer?.id ?? undefined,
      saleId: fromSale?.saleId,
      items: lines.map((i) => ({ productId: i.productId ?? undefined, productName: i.productName.trim(), dosage: i.dosage?.trim() || undefined, frequency: i.frequency || undefined, quantity: Number(i.quantity) || 1 })),
    };
    try {
      if (rx) await PrescriptionsApi.update(rx.id, payload);
      else await PrescriptionsApi.create(payload);
      toast.add({ title: rx ? "Prescription saved" : "Prescription added" });
      onSaved();
    } catch (e) {
      toast.add({ type: "error", title: "Not saved", description: apiError(e, "Try again.") });
    } finally {
      setSaving(false);
    }
  };

  return (
    <RecordDrawer
      open
      onOpenChange={(o) => !o && onClose()}
      variant="edit"
      width="lg"
      saving={saving}
      dirty={JSON.stringify(f) !== JSON.stringify(start)}
      title={rx ? `Edit ${ref(rx.id)}` : "New prescription"}
      subtitle={fromSale ? `From sale ${fromSale.receiptId}` : undefined}
      footer={
        <>
          <Button variant="outline" disabled={saving} onClick={onClose}>
            Cancel
          </Button>
          <Button disabled={saving} onClick={() => void save()}>
            {saving ? <Spinner /> : null}
            Save
          </Button>
        </>
      }
    >
      <div className="space-y-4">
        <div className="grid gap-4">
          <Field data-invalid={(tried && !!problems.patient) || undefined} className="relative sm:col-span-2">
            <FieldLabel htmlFor="rx-patient">Patient</FieldLabel>
            {f.customer ? (
              <div className="flex items-center gap-2 rounded-md border border-border px-3 py-1.5 text-sm">
                <span className="flex-1 font-medium">{f.customer.name}</span>
                <span className="text-xs text-muted-foreground">Registered customer</span>
                <Button size="icon-xs" variant="ghost" aria-label="Choose another patient" onClick={() => setF({ ...f, customer: null })}>
                  <XIcon />
                </Button>
              </div>
            ) : (
              <>
                <Input id="rx-patient" value={f.patientName} onChange={(e) => setF({ ...f, patientName: e.target.value })} aria-invalid={tried && !!problems.patient} autoComplete="off" />
                {patients.length ? (
                  <ul className="absolute top-full z-10 mt-1 w-full overflow-hidden rounded-md border border-border bg-popover text-sm shadow-md">
                    {patients.map((c) => (
                      <li key={c.id}>
                        <button type="button" className="flex w-full cursor-pointer justify-between px-3 py-1.5 text-left hover:bg-muted" onClick={() => setF({ ...f, customer: c, patientName: c.name, patientId: f.patientId || c.phone || "" })}>
                          <span>{c.name}</span>
                          <span className="text-xs text-muted-foreground tabular-nums">{formatPhone(c.phone)}</span>
                        </button>
                      </li>
                    ))}
                  </ul>
                ) : null}
              </>
            )}
            {tried && problems.patient ? <FieldError>{problems.patient}</FieldError> : <FieldDescription>Choose a registered customer to keep the prescription on their record, or type a name for a walk-in{fromSale ? " (left blank, it is saved as a walk-in patient)" : ""}.</FieldDescription>}
          </Field>
          <Field>
            <FieldLabel htmlFor="rx-pid">Patient number</FieldLabel>
            <Input id="rx-pid" value={f.patientId} onChange={(e) => setF({ ...f, patientId: e.target.value })} />
          </Field>
          <Field data-invalid={(tried && !!problems.date) || undefined}>
            <FieldLabel htmlFor="rx-date">Date written</FieldLabel>
            <Input id="rx-date" type="date" max={localToday()} value={f.dateIssued} onChange={(e) => setF({ ...f, dateIssued: e.target.value })} />
            {tried && problems.date ? <FieldError>{problems.date}</FieldError> : null}
          </Field>
          <Field className="sm:col-span-2">
            <FieldLabel htmlFor="rx-by">Prescriber</FieldLabel>
            <Input id="rx-by" value={f.prescriber} onChange={(e) => setF({ ...f, prescriber: e.target.value })} />
          </Field>
        </div>

        <fieldset className="space-y-2">
          <legend className="text-sm font-medium">Medicines</legend>
          {f.items.map((it, k) => (
            <div key={k} className="grid gap-2 rounded-md border border-border p-2 sm:grid-cols-[1fr_8rem_10rem_4.5rem_auto]">
              <NativeSelect
                aria-label={`Medicine ${k + 1}`}
                value={it.productId ? String(it.productId) : it.productName ? `name:${it.productName}` : ""}
                onChange={(e) => {
                  const p = products.find((x) => String(x.id) === e.target.value);
                  setItem(k, p ? { productId: p.id, productName: p.name } : { productId: null, productName: "" });
                }}
              >
                <NativeSelectOption value="">Choose a medicine</NativeSelectOption>
                {it.productName && !it.productId ? <NativeSelectOption value={`name:${it.productName}`}>{it.productName}</NativeSelectOption> : null}
                {products.map((p) => (
                  <NativeSelectOption key={p.id} value={String(p.id)}>
                    {p.name}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
              <Input aria-label={`Dose, medicine ${k + 1}`} placeholder="Dose, e.g. 500 mg" value={it.dosage ?? ""} onChange={(e) => setItem(k, { dosage: e.target.value })} />
              <NativeSelect aria-label={`How often, medicine ${k + 1}`} value={it.frequency ?? ""} onChange={(e) => setItem(k, { frequency: e.target.value })}>
                <NativeSelectOption value="">How often</NativeSelectOption>
                {FREQUENCIES.map((x) => (
                  <NativeSelectOption key={x} value={x}>
                    {x}
                  </NativeSelectOption>
                ))}
              </NativeSelect>
              <Input aria-label={`Quantity, medicine ${k + 1}`} inputMode="numeric" className="tabular-nums" value={String(it.quantity)} onChange={(e) => setItem(k, { quantity: Number(e.target.value.replace(/\D/g, "")) || 0 })} />
              <Button size="icon-sm" variant="ghost" aria-label={`Remove medicine ${k + 1}`} disabled={f.items.length === 1} onClick={() => setF({ ...f, items: f.items.filter((_, i) => i !== k) })}>
                <XIcon />
              </Button>
            </div>
          ))}
          <Button size="sm" variant="outline" onClick={() => setF({ ...f, items: [...f.items, { productName: "", dosage: "", frequency: "", quantity: 1 }] })}>
            <PlusIcon data-icon="inline-start" />
            Add medicine
          </Button>
          {tried && problems.items ? <p className="text-xs text-status-error-text">{problems.items}</p> : null}
        </fieldset>

        <Field orientation="horizontal" className="items-start justify-between rounded-lg border border-border p-3">
          <div className="space-y-0.5">
            <FieldLabel htmlFor="rx-alert">Alert the pharmacist before dispensing</FieldLabel>
            <FieldDescription>For an interaction, an allergy or a dose to check. Say why in the notes.</FieldDescription>
          </div>
          <Switch id="rx-alert" checked={f.hasAlert} onCheckedChange={(v) => setF({ ...f, hasAlert: v })} />
        </Field>
        <Field>
          <FieldLabel htmlFor="rx-notes">Notes</FieldLabel>
          <Textarea id="rx-notes" rows={2} value={f.notes} onChange={(e) => setF({ ...f, notes: e.target.value })} />
        </Field>
      </div>
    </RecordDrawer>
  );
}
