"use client";

/**
 * Prescriptions (PRD 4.4, CU-06), on the Medora design system (Stage 7) and the Customers API, Part 1: prescription
 * cards with their status timeline, a form drawer, and confirmations for cancelling and deleting. Every view and
 * change is logged by the API (CU-08), and only the caller's pharmacy's prescriptions are reachable.
 *
 * Named, not faked: dispensing marks the prescription dispensed; it doesn't pick a batch or take stock, which the sale
 * at the till does (so the design's dispense checklist with batch and expiry isn't used); the facility isn't recorded.
 */

import * as React from "react";
import { BanIcon, CheckIcon, PencilIcon, PlusIcon, SearchIcon, Trash2Icon, TriangleAlertIcon } from "lucide-react";

import { PanelError } from "@/components/medora/errors";
import { MedoraPageHeader } from "@/components/medora/page-header";
import { PrescriptionCard, type RxStatus } from "@/components/medora/records/parties";
import { ConfirmDialog } from "@/components/medora/confirm-dialog";
import { SensitiveNotice } from "@/components/medora/sensitive";
import { Button } from "@/components/ui/button";
import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/ui/input-group";
import { Spinner } from "@/components/ui/spinner";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { toast } from "@/components/ui/toast";
import { PrescriptionsApi } from "@/lib/api";
import { localDate, localToday } from "@/lib/format";
import { useMenuPermissions } from "@/lib/permissions";
import { PrescriptionForm, apiError, ref, type Rx } from "./prescription-form";
import { Surface } from "@/components/medora/surface";
import { Loading } from "@/components/medora/loading";

const STATUSES = ["All", "Pending", "Dispensed", "Cancelled", "Expired"];

export default function PrescriptionsPage() {
  const { can, loaded } = useMenuPermissions();
  const may = (action: string) => loaded && can("Customers/Prescriptions", action);
  const [rows, setRows] = React.useState<Rx[] | null>(null);
  const [failed, setFailed] = React.useState(false); // R12 (card 037): a failed load says so, with Try again
  const [search, setSearch] = React.useState("");
  const [status, setStatus] = React.useState("Pending");
  const [form, setForm] = React.useState<Rx | "new" | null>(null);
  const [confirm, setConfirm] = React.useState<{ rx: Rx; action: "cancel" | "delete" } | null>(null);
  const [busy, setBusy] = React.useState<number | null>(null);

  const load = React.useCallback(async () => {
    try {
      setRows(await PrescriptionsApi.getAll());
      setFailed(false);
    } catch (e) {
      setRows([]);
      setFailed(true);
      toast.add({ type: "error", title: "Couldn't load prescriptions", description: apiError(e, "Try again.") });
    }
  }, []);
  React.useEffect(() => {
    void load();
  }, [load]);

  const today = localToday();
  const all = rows ?? [];
  const pending = all.filter((r) => r.status === "Pending").length;
  const alerts = all.filter((r) => r.status === "Pending" && r.hasAlert).length;
  const t = search.trim().toLowerCase();
  const shown = all.filter(
    (r) =>
      (status === "All" || r.status === status) &&
      (!t || r.patientName.toLowerCase().includes(t) || (r.prescriber ?? "").toLowerCase().includes(t) || (r.items ?? []).some((i) => i.productName.toLowerCase().includes(t))),
  );

  const dispense = async (rx: Rx) => {
    setBusy(rx.id);
    try {
      await PrescriptionsApi.dispense(rx.id);
      toast.add({ title: `${ref(rx.id)} dispensed` });
      await load();
    } catch (e) {
      toast.add({ type: "error", title: "Not dispensed", description: apiError(e, "Try again.") });
    } finally {
      setBusy(null);
    }
  };

  return (
    <div className="medora mx-auto w-full max-w-6xl space-y-4">
      <MedoraPageHeader
        title="Prescriptions"
        description="Prescriptions written here or at the till."
        meta={rows && !failed ? [`${pending} pending`, ...(alerts ? [`${alerts} with an alert`] : []), `${all.filter((r) => r.status === "Dispensed" && (r.dateIssued ? localDate(r.dateIssued) : "") === today).length} dispensed today`] : []}
        metaLoading={!rows}
        primary={may("Create") ? { label: "New prescription", icon: PlusIcon, onSelect: () => setForm("new") } : undefined}
      />
      <SensitiveNotice kind="medical" />
      <Surface className="flex flex-wrap items-center gap-3">
        <InputGroup className="max-w-sm">
          <InputGroupAddon>
            <SearchIcon />
          </InputGroupAddon>
          <InputGroupInput placeholder="Patient, prescriber or medicine" value={search} onChange={(e) => setSearch(e.target.value)} aria-label="Search prescriptions" />
        </InputGroup>
        <Tabs value={status} onValueChange={(v) => setStatus(String(v))}>
          <TabsList variant="line">
            {STATUSES.map((s) => (
              <TabsTrigger key={s} value={s}>
                {s}
                {s === "Pending" && pending ? ` (${pending})` : ""}
              </TabsTrigger>
            ))}
          </TabsList>
        </Tabs>
      </Surface>
      {failed ? (
        <PanelError framed what="prescriptions" onRetry={() => void load()} />
      ) : !rows ? (
        <Loading what="prescriptions" shape="cards" rows={6} />
      ) : shown.length ? (
        <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
          {shown.map((rx) => (
            <div key={rx.id} className="space-y-1">
              {rx.hasAlert && rx.status === "Pending" ? (
                <p className="flex items-center gap-1.5 text-xs font-medium text-status-error-text">
                  <TriangleAlertIcon className="size-3.5" aria-hidden /> Alert: check before dispensing{rx.notes ? `: ${rx.notes}` : ""}
                </p>
              ) : null}
              <PrescriptionCard
                reference={ref(rx.id)}
                patient={rx.patientName}
                prescriber={rx.prescriber || "Prescriber not recorded"}
                facility={rx.patientId ? `Patient ${rx.patientId}` : "Facility not recorded"}
                date={localDate(rx.dateIssued ?? "")}
                status={(STATUSES.includes(rx.status) && rx.status !== "All" ? rx.status : "Pending") as RxStatus}
                items={(rx.items ?? []).map((i) => ({ name: i.productName, dose: [i.dosage, i.frequency].filter(Boolean).join(", ") || "No dose recorded", quantity: i.quantity }))}
                actions={
                  <>
                    {rx.status === "Pending" && may("Update") ? (
                      <>
                        <Button size="sm" variant="ghost" onClick={() => setConfirm({ rx, action: "cancel" })}>
                          <BanIcon data-icon="inline-start" />
                          Cancel
                        </Button>
                        <Button size="sm" variant="outline" onClick={() => setForm(rx)}>
                          <PencilIcon data-icon="inline-start" />
                          Edit
                        </Button>
                        <Button size="sm" disabled={busy === rx.id} onClick={() => void dispense(rx)}>
                          {busy === rx.id ? <Spinner /> : <CheckIcon data-icon="inline-start" />}
                          Dispense
                        </Button>
                      </>
                    ) : null}
                    {rx.status !== "Pending" && may("Delete") ? (
                      <Button size="sm" variant="ghost" className="text-status-error-text" onClick={() => setConfirm({ rx, action: "delete" })}>
                        <Trash2Icon data-icon="inline-start" />
                        Delete
                      </Button>
                    ) : null}
                  </>
                }
              />
            </div>
          ))}
        </div>
      ) : (
        <p className="py-12 text-center text-sm text-muted-foreground">{t ? "No prescriptions match." : status === "Pending" ? "Nothing waiting to be dispensed." : "No prescriptions here."}</p>
      )}

      {form ? (
        <PrescriptionForm
          rx={form === "new" ? null : form}
          onClose={() => setForm(null)}
          onSaved={() => {
            setForm(null);
            void load();
          }}
        />
      ) : null}
      <ConfirmDialog
        open={!!confirm}
        onOpenChange={(o) => !o && setConfirm(null)}
        level="A"
        title={confirm ? `${confirm.action === "cancel" ? "Cancel" : "Delete"} ${ref(confirm.rx.id)} for ${confirm.rx.patientName}?` : ""}
        consequences={
          confirm?.action === "cancel"
            ? ["It can't be dispensed after this, and stays in the list as cancelled."]
            : ["It's removed for good, with its medicines. The deletion is kept in the audit log."]
        }
        actionLabel={confirm?.action === "cancel" ? "Cancel prescription" : "Delete prescription"}
        busyLabel="Saving…"
        onConfirm={async () => {
          if (!confirm) return;
          try {
            if (confirm.action === "cancel") await PrescriptionsApi.cancel(confirm.rx.id);
            else await PrescriptionsApi.delete(confirm.rx.id);
          } catch (e) {
            throw new Error(apiError(e, "Not saved. Try again."));
          }
          toast.add({ title: `${ref(confirm.rx.id)} ${confirm.action === "cancel" ? "cancelled" : "deleted"}` });
          setConfirm(null);
          await load();
        }}
      />
    </div>
  );
}
