"use client";

import * as React from "react";
import { ArrowDownRightIcon, ArrowUpRightIcon, MinusIcon, SparklesIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

import { TONE_BOX, type Tone } from "./tones";

const n0 = (n: number) => n.toLocaleString("en-US", { maximumFractionDigits: 0 });
const n2 = (n: number) => n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });

/* --------------------------------- Monthly comparison --------------------------------- */

/** `partial`: the month isn't over, so comparing its total with a full month would mislead. */
export type MonthFigures = { month: string; gross: number; vat: number; transactions: number; partial?: boolean };

/** "Up 6.4%" / "Down 2.1%" / "Same": a change is a word and an arrow, and whether it's good depends on the figure. */
export function Change({ now, before, goodWhen = "up" }: { now: number; before?: number; goodWhen?: "up" | "down" }) {
  if (before == null || before === 0) return <span className="text-xs text-muted-foreground">–</span>;
  const pct = ((now - before) / before) * 100;
  if (Math.abs(pct) < 0.05)
    return (
      <span className="inline-flex items-center gap-0.5 text-xs text-muted-foreground">
        <MinusIcon className="size-3" aria-hidden /> Same
      </span>
    );
  const up = pct > 0;
  const good = goodWhen === "up" ? up : !up;
  const Icon = up ? ArrowUpRightIcon : ArrowDownRightIcon;
  return (
    <span className={cn("inline-flex items-center gap-0.5 text-xs font-medium whitespace-nowrap", good ? "text-status-success-text" : "text-status-error-text")}>
      <Icon className="size-3" aria-hidden />
      {up ? "Up" : "Down"} {Math.abs(pct).toFixed(1)}%
    </span>
  );
}

/**
 * Monthly comparison (PRD 8.5): each month's gross, VAT, net, transactions and average basket, against the
 * month before and the same month last year. Net is gross less VAT, so it reconciles with the P&L.
 */
export function MonthlyComparison({ months, lastYear }: { months: MonthFigures[]; lastYear: Record<string, MonthFigures> }) {
  return (
    <div className="overflow-x-auto rounded-lg border border-[var(--color-border-panel)] bg-card">
      <table className="w-full border-collapse text-sm tabular-nums">
        <caption className="sr-only">Sales by month</caption>
        <thead className="bg-[var(--color-bg-surface-subtle)] text-left text-xs text-muted-foreground">
          <tr>
            {["Month", "Gross", "VAT", "Net", "vs last month", "vs last year", "Sales", "Average basket"].map((h) => (
              <th key={h} scope="col" className={cn("px-3 py-2 font-medium", h !== "Month" && "text-right")}>
                {h}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className="divide-y divide-[var(--color-border-subtle)]">
          {months.map((m, i) => {
            const net = m.gross - m.vat;
            const prev = months[i + 1];
            const ly = lastYear[m.month.slice(0, 3)];
            return (
              <tr key={m.month}>
                <th scope="row" className="px-3 py-2 text-left font-medium whitespace-nowrap">
                  {m.month}
                </th>
                <td className="px-3 py-2 text-right">{n2(m.gross)}</td>
                <td className="px-3 py-2 text-right text-muted-foreground">{n2(m.vat)}</td>
                <td className="px-3 py-2 text-right font-semibold">{n2(net)}</td>
                <td className="px-3 py-2 text-right">
                  {m.partial ? <span className="text-xs text-muted-foreground">Part month</span> : <Change now={net} before={prev ? prev.gross - prev.vat : undefined} />}
                </td>
                <td className="px-3 py-2 text-right">
                  {m.partial ? <span className="text-xs text-muted-foreground">Part month</span> : <Change now={net} before={ly ? ly.gross - ly.vat : undefined} />}
                </td>
                <td className="px-3 py-2 text-right">{n0(m.transactions)}</td>
                <td className="px-3 py-2 text-right">{n2(m.gross / m.transactions)}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

/* ----------------------------------- Stock insights ----------------------------------- */

export type InsightBucket = "critical" | "stockouts" | "monitor" | "revenueStars" | "overstocked" | "deadStock" | "expiryRisk";
export type InsightItem = { name: string; detail: string; figure?: string };

const BUCKET: Record<InsightBucket, { title: string; rule: string; tone: Tone }> = {
  critical: { title: "Reorder now", rule: "Under 30 days of stock at the current rate of sale", tone: "error" },
  stockouts: { title: "Out of stock but selling", rule: "Zero stock, sold in the period", tone: "error" },
  monitor: { title: "Keep an eye on", rule: "30–120 days of stock", tone: "warning" },
  revenueStars: { title: "Protect these earners", rule: "Top revenue, 120–365 days of stock", tone: "success" },
  overstocked: { title: "Overstocked", rule: "Over a year of stock: stop ordering", tone: "info" },
  deadStock: { title: "Not selling", rule: "No sales in the period", tone: "neutral" },
  expiryRisk: { title: "Expiry risk", rule: "Batches expiring before they'll sell", tone: "warning" },
};

/**
 * Stock Insights panel (dashboard / Reports 8.6). Buckets are worked out from days of stock (stock ÷ average
 * daily units sold), not predicted. Each card says its rule, so the advice can be checked. "Never sold" is
 * its own bucket, not "plenty left".
 */
export function InsightCards({ buckets }: { buckets: Partial<Record<InsightBucket, { count: number; cash?: number; items: InsightItem[] }>> }) {
  return (
    <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
      {(Object.keys(BUCKET) as InsightBucket[])
        .filter((k) => buckets[k])
        .map((k) => {
          const b = buckets[k]!;
          const meta = BUCKET[k];
          return (
            <section key={k} aria-label={meta.title} className="flex flex-col rounded-lg border border-[var(--color-border-panel)] bg-card p-3">
              <div className="flex items-baseline justify-between gap-2">
                <h4 className="text-sm font-semibold">{meta.title}</h4>
                <span className={cn("rounded-full border px-2 text-xs font-semibold tabular-nums", TONE_BOX[meta.tone])}>{b.count}</span>
              </div>
              <p className="text-xs text-muted-foreground">{meta.rule}</p>
              {b.cash ? <p className="mt-1 text-xs font-medium tabular-nums">KES {n2(b.cash)} at cost</p> : null}
              <ul className="mt-2 space-y-1 text-sm">
                {b.items.slice(0, 3).map((it) => (
                  <li key={it.name} className="flex items-baseline justify-between gap-2">
                    <span className="min-w-0">
                      <span className="block truncate">{it.name}</span>
                      <span className="block text-xs text-muted-foreground">{it.detail}</span>
                    </span>
                    {it.figure ? <span className="shrink-0 text-xs font-medium tabular-nums">{it.figure}</span> : null}
                  </li>
                ))}
              </ul>
              {b.count > 3 ? <p className="mt-auto pt-2 text-xs text-muted-foreground">and {b.count - 3} more</p> : null}
            </section>
          );
        })}
    </div>
  );
}

export type Narrative = { state: "ready"; text: string; at: string } | { state: "loading" } | { state: "unavailable"; reason: string };

/**
 * The written summary above the cards. The model writes prose from figures the server worked out, so it
 * can't invent numbers; it says it's AI-written. When it's unavailable (no key, offline desktop, error) the
 * paragraph is simply absent: the cards stand on their own.
 */
export function InsightNarrative({ narrative, onRefresh }: { narrative: Narrative; onRefresh?: () => void }) {
  if (narrative.state === "unavailable") return null;
  return (
    <div className="rounded-lg border border-[var(--color-border-panel)] bg-card p-3" aria-busy={narrative.state === "loading"}>
      <p className="mb-1.5 flex items-center gap-1.5 text-xs font-medium text-muted-foreground">
        <SparklesIcon className="size-3.5" aria-hidden /> Summary written by AI from the figures below. Check before acting.
      </p>
      {narrative.state === "loading" ? (
        <div className="space-y-1.5">
          {[100, 92, 70].map((w) => (
            <div key={w} className="h-3.5 animate-pulse rounded-sm bg-muted" style={{ width: `${w}%` }} />
          ))}
        </div>
      ) : (
        <>
          <p className="text-sm leading-relaxed">{narrative.text}</p>
          <div className="mt-1.5 flex items-center justify-between gap-2 text-xs text-muted-foreground">
            <span>Written {narrative.at}; rewritten only when the figures change.</span>
            {onRefresh ? (
              <Button size="xs" variant="ghost" onClick={onRefresh}>
                Refresh
              </Button>
            ) : null}
          </div>
        </>
      )}
    </div>
  );
}
