"use client";

import * as React from "react";
import { InfoIcon } from "lucide-react";

import { DashboardGrid, PanelPermissions, type DashboardPanel, type PanelGrants } from "@/components/medora/dashboard-panels";
import { AgeingChart, BranchMoneyChart, BranchSalesChart, MethodDonut, SeriesLineChart, TargetRing } from "@/components/medora/report-charts";
import { StatTile } from "@/components/medora/records/finance";
import { MoneyCard } from "@/components/medora/money-card";
import { TONE_BOX } from "@/components/medora/tones";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";
import { toast } from "@/components/ui/toast";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { cn } from "@/lib/utils";

const ROLES = ["Admin", "Pharmacist", "Cashier", "Inventory Manager"];

const PANELS: DashboardPanel[] = [
  { id: "revenue", title: "Revenue", description: "Sales for the period, excluding held sales.", group: "Headline figures", ref: "DB-03" },
  { id: "transactions", title: "Transactions", description: "Number of completed sales.", group: "Headline figures", ref: "DB-03" },
  { id: "gross-profit", title: "Gross profit", description: "Revenue excluding VAT, less cost of goods.", group: "Headline figures", sensitive: true, ref: "DB-03" },
  { id: "expenses", title: "Expenses", description: "Expenses paid in the period.", group: "Headline figures", sensitive: true, ref: "DB-03" },
  { id: "net-profit", title: "Net profit", description: "Gross profit less expenses.", group: "Headline figures", sensitive: true, ref: "DB-03" },
  { id: "payment-methods", title: "Sales by payment method", description: "Cash, M-Pesa, card and credit.", group: "Sales", span: 4, ref: "DB-08" },
  { id: "stock-value", title: "Stock value", description: "Stock at cost, from batches.", group: "Stock", sensitive: true, span: 4, ref: "DB-06" },
  { id: "branch-sales", title: "Sales by branch", description: "Cash and credit sales per branch.", group: "Sales", span: 6, ref: "DB-05" },
  { id: "money-summary", title: "Money summary", description: "Owed to us / We owe, Tax, Stock and Costs.", group: "Money", sensitive: true, span: 12, ref: "DB-07" },
  { id: "cash-bank", title: "Cash & bank", description: "Cash drawers, M-Pesa tills, card terminals and banks, per branch.", group: "Money", sensitive: true, span: 12, ref: "DB-13" },
  { id: "sales-target", title: "Sales target", description: "Sales to date against this month's target.", group: "Sales", span: 4, ref: "DB-17" },
  { id: "stock-value-trend", title: "Stock value over time", description: "Stock at cost and at selling price, day by day.", group: "Stock", sensitive: true, span: 8, ref: "DB-16" },
  { id: "stock-alerts", title: "Stock alerts", description: "Reorder, out of stock, overstock and expiring counts.", group: "Stock", span: 6, ref: "DB-10" },
];

const SAVED: PanelGrants = {
  Pharmacist: ["revenue", "transactions", "payment-methods", "stock-alerts"],
  Cashier: ["transactions", "payment-methods"],
  "Inventory Manager": ["stock-alerts", "stock-value"],
};

const kes = (n: number) => `KES ${n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;

function Card({ title, rows }: { title: string; rows: [string, string, string?][] }) {
  return (
    <div className="h-full rounded-lg border border-border bg-card p-3">
      <p className="text-xs font-medium text-muted-foreground">{title}</p>
      <dl className="mt-2 space-y-1.5 text-sm">
        {rows.map(([k, v, note]) => (
          <div key={k} className="flex items-baseline justify-between gap-3">
            <dt className="text-muted-foreground">{k}</dt>
            <dd className={cn("font-medium tabular-nums", note && "text-status-error-text")}>
              {v}
              {note ? <span className="block text-right text-[11px] font-normal">{note}</span> : null}
            </dd>
          </div>
        ))}
      </dl>
    </div>
  );
}

function ChartCardShell({ title, hint, children }: { title: string; hint: string; children: React.ReactNode }) {
  return (
    <div className="h-full space-y-2 rounded-lg border border-border bg-card p-3">
      <div>
        <p className="text-xs font-medium text-muted-foreground">{title}</p>
        <p className="text-[11px] text-muted-foreground">{hint}</p>
      </div>
      {children}
    </div>
  );
}

function renderPanel(p: DashboardPanel) {
  switch (p.id) {
    case "revenue":
      return <StatTile label="Revenue" value={kes(1284600)} delta={6.4} hint="1–20 Oct, all branches" />;
    case "transactions":
      return <StatTile label="Transactions" value="3,412" delta={2.1} hint="1–20 Oct" />;
    case "gross-profit":
      return <StatTile label="Gross profit" value={kes(442300)} delta={-1.8} hint="On revenue excluding VAT" />;
    case "expenses":
      return <StatTile label="Expenses" value={kes(194350)} delta={3.5} hint="Paid 1–20 Oct" />;
    case "net-profit":
      return <StatTile label="Net profit" value={kes(247950)} delta={4.2} hint="Gross profit less expenses" />;
    case "money-summary":
      // Card 040 addition: owed to us and we owe by age (the Accounts ageing chart), then Tax, Stock and Costs as figures
      return (
        <MoneyCard
          title="Money summary"
          asAt="20 Oct 2026"
          chart={
            <AgeingChart
              rows={[
                { label: "Owed to us", buckets: [58200, 21300, 9800, 7120] },
                { label: "We owe", buckets: [92400, 31870, 14100, 7900] },
              ]}
            />
          }
          groups={[
            { name: "Tax", rows: [{ label: "VAT due", value: kes(31560) }, { label: "PAYE and statutory due", value: kes(48210) }] },
            { name: "Stock", rows: [{ label: "At cost, from batches", value: kes(684210) }] },
            { name: "Costs", rows: [{ label: "Expenses this period", value: kes(194350) }, { label: "Payroll, October", value: kes(412600) }] },
          ]}
        />
      );
    case "cash-bank":
      // Card 040 addition: each branch's drawer, M-Pesa and card drawn; banks are pharmacy-wide, so listed
      return (
        <MoneyCard
          title="Cash and bank"
          asAt="20 Oct 2026"
          chart={
            <BranchMoneyChart
              rows={[
                { branch: "Westlands Main", drawer: 9850, mpesa: 52400, card: 7350 },
                { branch: "Kilimani", drawer: -1200, mpesa: 18600, card: 2100 },
                { branch: "Nyali", drawer: 5400, mpesa: 9800, card: 0 },
                { branch: "Milimani", drawer: 3200, mpesa: 5250, card: 0 },
              ]}
              explain={{ "Kilimani:drawer": "a drop was recorded twice." }}
            />
          }
          groups={[{ name: "Banks", rows: [{ label: "Equity Bank", value: kes(412300) }, { label: "KCB", value: kes(85300) }] }]}
        />
      );
    case "payment-methods":
      return (
        <ChartCardShell title="Sales by payment method" hint="1–20 Oct, all branches">
          <MethodDonut
            caption="Total sales"
            rows={[
              { method: "M-Pesa", amount: 741200 },
              { method: "Cash", amount: 398500 },
              { method: "Card", amount: 96400 },
              { method: "Credit", amount: 48500 },
            ]}
          />
        </ChartCardShell>
      );
    case "branch-sales":
      return (
        <ChartCardShell title="Sales by branch" hint="1–20 Oct, paid at the till and on credit">
          <BranchSalesChart
            compact
            rows={[
              { branch: "Westlands Main", paid: 582300, credit: 30100 },
              { branch: "Kilimani", paid: 292100, credit: 9800 },
              { branch: "Nyali", paid: 237900, credit: 6200 },
              { branch: "Milimani", paid: 123800, credit: 2400 },
            ]}
          />
        </ChartCardShell>
      );
    case "stock-alerts":
      // Count with status (02-data-display §4): the count, its badge, the list behind it; a zero is a plain line
      return (
        <div className="space-y-2">
          <p className="text-sm font-semibold">Stock alerts</p>
          <div className="grid auto-rows-fr gap-3 sm:grid-cols-2 xl:grid-cols-4">
            {(
              [
                ["Need reordering", 18, "Low stock", "Under 30 days of stock"],
                ["Out of stock but selling", 4, "Out of stock", "Zero stock, sold in the last 90 days"],
                ["Overstocked", 7, "Overstocked", `${kes(84300)} tied up`],
                ["Expiring before they sell", 11, "Expiring", "Batches at risk, within 60 days"],
              ] as const
            ).map(([label, n, status, line]) => (
              <StatTile key={label} label={label} value={String(n)} status={n ? status : undefined} hint={line} onSelect={n ? () => toast.add({ title: `Opens the ${n} items: ${label.toLowerCase()}` }) : undefined} linkLabel={`View the ${n} items`} />
            ))}
          </div>
        </div>
      );
    case "sales-target":
      return (
        <ChartCardShell title="Sales target" hint="October 2026, all branches">
          <TargetRing value={1284600} target={1800000} period="October 2026" />
        </ChartCardShell>
      );
    case "stock-value-trend":
      return (
        <ChartCardShell title="Stock value over time" hint="1–20 Oct, all branches">
          <SeriesLineChart
            label="Stock value over time"
            measure="last"
            series={[
              { key: "cost", label: "At cost" },
              { key: "selling", label: "At selling price" },
            ]}
            points={[
              { label: "1 Oct", cost: 702150, selling: 1050750 },
              { label: "6 Oct", cost: 676900, selling: 1012960 },
              { label: "7 Oct", cost: 733400, selling: 1097510 },
              { label: "14 Oct", cost: 694300, selling: 1039000 },
              { label: "15 Oct", cost: 750800, selling: 1123550 },
              { label: "20 Oct", cost: 684210, selling: 1023900 },
            ]}
            caveat="Past days are valued at today's costs."
          />
        </ChartCardShell>
      );
    case "stock-value":
      return <Card title="Stock value" rows={[["At cost, from batches", kes(684210)], ["At selling price", kes(1023900)]]} />;
    default:
      return null;
  }
}

export function DashboardPanelsPattern() {
  const [saved, setSaved] = React.useState<PanelGrants>(SAVED);
  const [draft, setDraft] = React.useState<PanelGrants>(SAVED);
  const [viewAs, setViewAs] = React.useState("Cashier");
  const [branch, setBranch] = React.useState("All branches");
  const [saving, setSaving] = React.useState(false);

  const changed = ROLES.filter((r) => r !== "Admin" && JSON.stringify([...(draft[r] ?? [])].sort()) !== JSON.stringify([...(saved[r] ?? [])].sort()));
  const allowed = viewAs === "Admin" ? PANELS.map((p) => p.id) : (draft[viewAs] ?? []);
  const sensitiveOn = ROLES.filter((r) => r !== "Admin").flatMap((r) => PANELS.filter((p) => p.sensitive && (draft[r] ?? []).includes(p.id) && !(saved[r] ?? []).includes(p.id)).map((p) => `${p.title} to ${r}`));

  return (
    <div className="space-y-6 p-4">
      <div className="space-y-3">
        <div>
          <h3 className="text-base font-semibold">Dashboard panels (Settings, Assign roles)</h3>
          <p className="text-sm text-muted-foreground">Turn a panel on for a role and its figures appear on that role&apos;s dashboard. The server applies the same rule, so a hidden panel&apos;s figures are never sent.</p>
        </div>
        <PanelPermissions panels={PANELS} roles={ROLES} grants={draft} onChange={setDraft} />
        {changed.length ? (
          <div role="region" aria-label="Unsaved changes" className="sticky bottom-0 z-10 flex flex-wrap items-center gap-3 border-t border-[var(--color-border-subtle)] bg-card py-3 shadow-[0_-4px_12px_-6px_rgb(0_17_16/0.18)]">
            <p className="mr-auto text-sm">
              <span className="font-medium">Unsaved changes</span> <span className="text-muted-foreground">for {changed.join(", ")}</span>
              {sensitiveOn.length ? <span className="block text-xs text-status-warning-text">Gives sensitive figures: {sensitiveOn.join("; ")}.</span> : null}
            </p>
            <Button variant="ghost" disabled={saving} onClick={() => setDraft(saved)}>
              Discard
            </Button>
            <Button
              disabled={saving}
              onClick={() => {
                setSaving(true);
                setTimeout(() => {
                  setSaving(false);
                  setSaved(draft);
                  toast.add({ title: "Dashboard panels saved", description: `Changed for ${changed.join(", ")}. Applies at their next page load.` });
                }, 800);
              }}
            >
              {saving ? <Spinner /> : null}
              {saving ? "Saving…" : "Save changes"}
            </Button>
          </div>
        ) : null}
      </div>

      <div className="space-y-3">
        <div className="flex flex-wrap items-center gap-3">
          <h3 className="text-base font-semibold">Preview the dashboard as</h3>
          <ToggleGroup variant="outline" size="sm" spacing={0} aria-label="Preview as" value={[viewAs]} onValueChange={(v: string[]) => v[0] && setViewAs(v[0])}>
            {ROLES.map((r) => (
              <ToggleGroupItem key={r} value={r}>
                {r}
              </ToggleGroupItem>
            ))}
          </ToggleGroup>
        </div>
        {changed.includes(viewAs) ? (
          <p className={cn("flex items-center gap-2 rounded-md border px-3 py-2 text-sm", TONE_BOX.info)}>
            <InfoIcon className="size-4 shrink-0" aria-hidden /> The preview includes your unsaved changes for {viewAs}.
          </p>
        ) : null}
        <div className="flex flex-wrap items-center gap-3">
          <span className="text-sm text-muted-foreground">Dashboard filter:</span>
          <ToggleGroup variant="outline" size="sm" spacing={0} aria-label="Branch" value={[branch]} onValueChange={(v: string[]) => v[0] && setBranch(v[0])}>
            {["All branches", "Westlands Main"].map((b) => (
              <ToggleGroupItem key={b} value={b}>
                {b}
              </ToggleGroupItem>
            ))}
          </ToggleGroup>
          {branch !== "All branches" && allowed.includes("branch-sales") ? <span className="text-xs text-muted-foreground">Sales by branch is hidden: one branch is selected.</span> : null}
        </div>
        <div className="rounded-lg bg-muted/40 p-3">
          {/* DB-05: comparing branches means nothing when the filter is one branch, so the panel closes up. */}
          <DashboardGrid panels={PANELS} allowed={branch === "All branches" ? allowed : allowed.filter((id) => id !== "branch-sales")} render={renderPanel} role={viewAs} />
        </div>
      </div>
    </div>
  );
}
