// Per-workload rightsizing table — the core interactive section. Rows render
// grouped by the engine-assigned component group (`w.group`: vmcluster /
// vmalert / loki / diagnosis / kube-prome / metrics-integration / other)
// under collapsible summary headers — vmcluster expanded by default, the
// rest collapsed.
// Text/scenario/confidence filters auto-expand the groups they match, and a
// click-to-expand row reveals rationale + observed avg/max detail plus the
// live usage trend chart.

import { Fragment, useMemo, useState } from "react";
import { workloadKeyOf, type Scenario, type WorkloadRow } from "@/engine/classify";
import { fixed } from "@/lib/fmt";
import { groupLabel, groupRank } from "@/lib/workload-groups";
import { Badge } from "@/components/ui/Badge";
import { inputClassName } from "@/components/ui/input";
import { DataTable, Td, Th, rowKeyActivate } from "@/components/ui/DataTable";
import { Empty } from "@/components/ui/Empty";
import { UtilBar } from "@/components/ui/UtilBar";
import { WorkloadTrendChart } from "@/components/regions/WorkloadTrendChart";

/** Scenario filter options, keyed off the engine's Scenario union so a new
 *  engine-side scenario must land here too (Record is exhaustive). */
const SCENARIO_LABELS: Record<Scenario, string> = {
  idle: "idle",
  default_burstable: "default_burstable",
};

const COLS = 12;

type SortKey =
  | "npods"
  | "reqCpu"
  | "reqMemGib"
  | "newReqCpu"
  | "newReqMemGib"
  | "maxPerReqCpu"
  | "maxPerReqMem";

function f(v: number | null | undefined, digits = 2): string {
  return fixed(v, digits) ?? "—";
}

const rowKey = workloadKeyOf;

function sumBy(rows: WorkloadRow[], pick: (w: WorkloadRow) => number): number {
  return rows.reduce((acc, w) => acc + pick(w), 0);
}

export function WorkloadTable({
  workloads,
  regionKey,
}: {
  workloads: WorkloadRow[];
  regionKey: string;
}) {
  const [q, setQ] = useState("");
  const [scenario, setScenario] = useState("all");
  const [conf, setConf] = useState("all");
  const [sortKey, setSortKey] = useState<SortKey>("reqCpu");
  const [desc, setDesc] = useState(true);
  const [expanded, setExpanded] = useState<string | null>(null);
  // vmcluster starts expanded — the fleet's heaviest components are the
  // usual reason for opening the Workloads tab.
  const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set(["vmcluster"]));

  const filtered = useMemo(() => {
    const needle = q.trim().toLowerCase();
    return workloads.filter((w) => {
      if (needle && !`${w.ns} ${w.name}`.toLowerCase().includes(needle)) return false;
      if (scenario !== "all" && w.scenario !== scenario) return false;
      if (conf !== "all" && w.confidence !== conf) return false;
      return true;
    });
  }, [workloads, q, scenario, conf]);

  const sorted = useMemo(() => {
    return [...filtered].sort((a, b) => (desc ? b[sortKey] - a[sortKey] : a[sortKey] - b[sortKey]));
  }, [filtered, sortKey, desc]);

  // Bucket the sorted rows by group — bucketing preserves within-group order,
  // so the column sort keeps applying inside each group.
  const byGroup = useMemo(() => {
    const buckets = new Map<string, WorkloadRow[]>();
    for (const w of sorted) {
      const b = buckets.get(w.group);
      if (b) b.push(w);
      else buckets.set(w.group, [w]);
    }
    return [...buckets.entries()]
      .map(([id, rows]) => ({ id, rows }))
      .sort((a, b) => groupRank(a.id) - groupRank(b.id));
  }, [sorted]);

  // While a filter is active every visible group shows its matches expanded;
  // manual collapse state only applies when no filter is active.
  const filtersActive = q.trim() !== "" || scenario !== "all" || conf !== "all";
  const groupOpen = (id: string): boolean => filtersActive || expandedGroups.has(id);
  const toggleGroup = (id: string) => {
    if (filtersActive) return;
    setExpandedGroups((cur) => {
      const next = new Set(cur);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const toggle = (key: SortKey) => {
    if (key === sortKey) {
      setDesc((d) => !d);
    } else {
      setSortKey(key);
      setDesc(true);
    }
  };
  const sortedMarker = (key: SortKey) => (sortKey === key ? (desc ? "desc" : "asc") : false);

  if (workloads.length === 0) {
    return <Empty>No workload usage collected for this region.</Empty>;
  }

  const selectCls = inputClassName;
  return (
    <div>
      <div className="mb-3 flex flex-wrap items-center gap-2">
        <input
          value={q}
          onChange={(e) => setQ(e.target.value)}
          placeholder="search ns or name…"
          aria-label="search ns or name"
          className={`${selectCls} w-56`}
        />
        <select aria-label="filter by scenario" value={scenario} onChange={(e) => setScenario(e.target.value)} className={selectCls}>
          <option value="all">all scenarios</option>
          {Object.entries(SCENARIO_LABELS).map(([id, label]) => (
            <option key={id} value={id}>
              {label}
            </option>
          ))}
        </select>
        <select aria-label="filter by confidence" value={conf} onChange={(e) => setConf(e.target.value)} className={selectCls}>
          <option value="all">all confidence</option>
          <option value="low">low</option>
          <option value="medium">medium</option>
        </select>
        <span className="ml-auto text-xs text-text-muted">
          {sorted.length} of {workloads.length} workloads
        </span>
      </div>

      <DataTable>
        <thead>
          <tr>
            <Th>Workload</Th>
            <Th numeric onClick={() => toggle("npods")} sorted={sortedMarker("npods")}>Pods</Th>
            <Th numeric onClick={() => toggle("reqCpu")} sorted={sortedMarker("reqCpu")}>Req CPU</Th>
            <Th numeric onClick={() => toggle("reqMemGib")} sorted={sortedMarker("reqMemGib")}>Req mem</Th>
            <Th numeric onClick={() => toggle("newReqCpu")} sorted={sortedMarker("newReqCpu")}>New CPU</Th>
            <Th numeric onClick={() => toggle("newReqMemGib")} sorted={sortedMarker("newReqMemGib")}>New mem</Th>
            <Th numeric onClick={() => toggle("maxPerReqCpu")} sorted={sortedMarker("maxPerReqCpu")}>Max/req CPU</Th>
            <Th numeric onClick={() => toggle("maxPerReqMem")} sorted={sortedMarker("maxPerReqMem")}>Max/req mem</Th>
            <Th>CPU util</Th>
            <Th>Mem util</Th>
            <Th>Scenario</Th>
            <Th>Conf</Th>
          </tr>
        </thead>
        <tbody>
          {byGroup.length === 0 ? (
            <tr>
              <td colSpan={COLS} className="px-3 py-6 text-center text-xs text-text-muted">
                No workloads match the active filters.
              </td>
            </tr>
          ) : null}
          {byGroup.map((g) => {
            const open = groupOpen(g.id);
            const pods = sumBy(g.rows, (w) => w.npods);
            const reqCpu = sumBy(g.rows, (w) => w.reqCpu);
            const reqMem = sumBy(g.rows, (w) => w.reqMemGib);
            const newCpu = sumBy(g.rows, (w) => w.totalNewReqCpu);
            const newMem = sumBy(g.rows, (w) => w.totalNewReqMemGib);
            const statCls = "text-xs tabular-nums text-text-muted";
            return (
              <Fragment key={g.id}>
                <tr
                  onClick={() => toggleGroup(g.id)}
                  onKeyDown={rowKeyActivate(() => toggleGroup(g.id))}
                  tabIndex={0}
                  className="cursor-pointer hover:bg-surface-1"
                >
                  <td colSpan={COLS} className="border-b border-surface-2/50 bg-surface-1/40 px-3 py-2">
                    <div className="flex flex-wrap items-center gap-x-4 gap-y-1">
                      <span className="text-sm font-medium">
                        {open ? "▾" : "▸"} {groupLabel(g.id)}
                      </span>
                      <span className={statCls}>
                        {g.rows.length} {g.rows.length === 1 ? "workload" : "workloads"}
                      </span>
                      <span className={statCls}>
                        {pods} {pods === 1 ? "pod" : "pods"}
                      </span>
                      <span className={statCls}>req {f(reqCpu)} CPU / {f(reqMem)} GiB</span>
                      <span className={statCls}>new {f(newCpu)} CPU / {f(newMem)} GiB</span>
                    </div>
                  </td>
                </tr>
                {open
                  ? g.rows.map((w) => {
                      const key = rowKey(w);
                      const newCpuTone =
                        w.newReqCpu < w.reqCpu ? "text-success" : w.newReqCpu > w.reqCpu ? "text-warning" : "";
                      const newMemTone =
                        w.newReqMemGib < w.reqMemGib ? "text-success" : w.newReqMemGib > w.reqMemGib ? "text-warning" : "";
                      return (
                        <Fragment key={key}>
                          <tr
                            onClick={() => setExpanded((cur) => (cur === key ? null : key))}
                            onKeyDown={rowKeyActivate(() => setExpanded((cur) => (cur === key ? null : key)))}
                            tabIndex={0}
                            className={`cursor-pointer hover:bg-surface-1 ${expanded === key ? "bg-surface-1" : ""}`}
                          >
                            <Td>
                              <div className="font-medium">{w.name}</div>
                              <div className="text-xs text-text-muted">
                                {w.kind} · {w.ns}
                              </div>
                            </Td>
                            <Td numeric>{w.npods}</Td>
                            <Td numeric>{f(w.reqCpu)}</Td>
                            <Td numeric>{f(w.reqMemGib)}</Td>
                            <Td numeric className={newCpuTone}>{f(w.newReqCpu)}</Td>
                            <Td numeric className={newMemTone}>{f(w.newReqMemGib)}</Td>
                            <Td numeric>{f(w.maxPerReqCpu)}×</Td>
                            <Td numeric>{f(w.maxPerReqMem)}×</Td>
                            <Td><UtilBar value={w.maxCpuUtil} label="max CPU utilization" /></Td>
                            <Td><UtilBar value={w.maxMemUtil} label="max memory utilization" /></Td>
                            <Td>
                              <Badge tone={w.scenario === "idle" ? "info" : "neutral"}>{w.scenario}</Badge>
                            </Td>
                            <Td>
                              <Badge tone={w.confidence === "low" ? "warn" : "neutral"}>{w.confidence}</Badge>
                            </Td>
                          </tr>
                          {expanded === key ? (
                            <tr>
                              <td colSpan={COLS} className="border-b border-surface-2/50 bg-surface-1/50 px-4 py-3">
                                <div className="flex flex-wrap gap-x-8 gap-y-1 text-xs text-text-secondary">
                                  <span>avg CPU <span className="tabular-nums">{f(w.avgCpu)}</span></span>
                                  <span>max CPU <span className="tabular-nums">{f(w.maxCpu)}</span></span>
                                  <span>avg mem <span className="tabular-nums">{f(w.avgMemGib)}</span> GiB</span>
                                  <span>max mem <span className="tabular-nums">{f(w.maxMemGib)}</span> GiB</span>
                                  <span>lim CPU <span className="tabular-nums">{f(w.limCpu)}</span></span>
                                  <span>lim mem <span className="tabular-nums">{f(w.limMemGib)}</span> GiB</span>
                                  <span>burst ratio <span className="tabular-nums">{f(w.burstRatio)}</span></span>
                                  <span>new lim <span className="tabular-nums">{f(w.newLimCpu)}</span> CPU / <span className="tabular-nums">{f(w.newLimMemGib)}</span> GiB</span>
                                </div>
                                <p className="mt-2 text-xs text-text-muted">{w.rationale}</p>
                                <WorkloadTrendChart regionKey={regionKey} ns={w.ns} kind={w.kind} name={w.name} />
                              </td>
                            </tr>
                          ) : null}
                        </Fragment>
                      );
                    })
                  : null}
              </Fragment>
            );
          })}
        </tbody>
      </DataTable>
    </div>
  );
}
