"use client";

import { useState, useCallback, useMemo } from "react";
import { trpc } from "~/lib/trpc/client.js";
import { DateInput } from "~/components/ui/DateInput.js";
import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js";
import { formatMoney, formatDate } from "~/lib/format.js";

// ── Types ────────────────────────────────────────────────────────────────────

interface BaselineAssignment {
  id: string;
  resourceId: string | null;
  resourceName: string;
  resourceEid: string;
  lcrCents: number;
  roleId: string | null;
  roleName: string;
  roleColor: string | null;
  startDate: string;
  endDate: string;
  hoursPerDay: number;
  status: string;
  costCents: number;
  totalHours: number;
  workingDays: number;
}

interface BaselineDemand {
  id: string;
  roleId: string | null;
  roleName: string;
  roleColor: string | null;
  startDate: string;
  endDate: string;
  hoursPerDay: number;
  headcount: number;
  status: string;
}

interface Baseline {
  project: {
    id: string;
    name: string;
    shortCode: string;
    startDate: Date | string;
    endDate: Date | string;
    budgetCents: number | null;
  };
  assignments: BaselineAssignment[];
  demands: BaselineDemand[];
  totalCostCents: number;
  totalHours: number;
  budgetCents: number | null;
}

interface ResourceOption {
  id: string;
  displayName: string;
  eid: string;
  lcrCents: number;
}

interface RoleOption {
  id: string;
  name: string;
  color: string | null;
}

interface ScenarioRow {
  key: string;
  assignmentId?: string;
  resourceId: string;
  roleId: string;
  startDate: string;
  endDate: string;
  hoursPerDay: number;
  remove?: boolean;
}

interface ScenarioPlannerProps {
  projectId: string;
  baseline: Baseline;
  resources: ResourceOption[];
  roles: RoleOption[];
}

// ── Helpers ──────────────────────────────────────────────────────────────────

function toISODate(d: Date | string): string {
  if (typeof d === "string") return d.split("T")[0] ?? d;
  return d.toISOString().split("T")[0] ?? "";
}

let nextKey = 1;
function genKey(): string {
  return `new-${nextKey++}`;
}

// ── Component ────────────────────────────────────────────────────────────────

export function ScenarioPlanner({ projectId, baseline, resources, roles }: ScenarioPlannerProps) {
  const projectStart = toISODate(baseline.project.startDate);
  const projectEnd = toISODate(baseline.project.endDate);

  // Initialize scenario rows from baseline assignments
  const initialRows: ScenarioRow[] = baseline.assignments.map((a) => ({
    key: a.id,
    assignmentId: a.id,
    resourceId: a.resourceId ?? "",
    roleId: a.roleId ?? "",
    startDate: toISODate(a.startDate),
    endDate: toISODate(a.endDate),
    hoursPerDay: a.hoursPerDay,
  }));

  const [rows, setRows] = useState<ScenarioRow[]>(initialRows);
  const [showApplyConfirm, setShowApplyConfirm] = useState(false);

  // Simulation mutation
  const simulateMut = trpc.scenario.simulate.useMutation();
  const applyMut = trpc.scenario.apply.useMutation();

  // Derived: has the scenario diverged from baseline?
  const isDirty = useMemo(() => {
    if (rows.length !== initialRows.length) return true;
    return rows.some((r, i) => {
      const init = initialRows[i];
      if (!init) return true;
      return (
        r.resourceId !== init.resourceId ||
        r.roleId !== init.roleId ||
        r.startDate !== init.startDate ||
        r.endDate !== init.endDate ||
        r.hoursPerDay !== init.hoursPerDay ||
        r.remove
      );
    });
  }, [rows, initialRows]);

  // Resource lookup map
  const resourceMap = useMemo(() => new Map(resources.map((r) => [r.id, r])), [resources]);
  const roleMap = useMemo(() => new Map(roles.map((r) => [r.id, r])), [roles]);

  // ── Row Handlers ─────────────────────────────────────────────────────────

  const updateRow = useCallback((key: string, updates: Partial<ScenarioRow>) => {
    setRows((prev) => prev.map((r) => (r.key === key ? { ...r, ...updates } : r)));
  }, []);

  const removeRow = useCallback((key: string) => {
    setRows((prev) => {
      const row = prev.find((r) => r.key === key);
      if (!row) return prev;
      // If it's an existing assignment, mark for removal instead of deleting
      if (row.assignmentId) {
        return prev.map((r) => (r.key === key ? { ...r, remove: true } : r));
      }
      // New row — just remove it
      return prev.filter((r) => r.key !== key);
    });
  }, []);

  const restoreRow = useCallback((key: string) => {
    setRows((prev) => prev.map((r) => (r.key === key ? { ...r, remove: false } : r)));
  }, []);

  const addRow = useCallback(() => {
    setRows((prev) => [
      ...prev,
      {
        key: genKey(),
        resourceId: "",
        roleId: "",
        startDate: projectStart,
        endDate: projectEnd,
        hoursPerDay: 8,
      },
    ]);
  }, [projectStart, projectEnd]);

  const resetScenario = useCallback(() => {
    setRows(initialRows);
    simulateMut.reset();
  }, [initialRows, simulateMut]);

  // ── Simulate ─────────────────────────────────────────────────────────────

  const runSimulation = useCallback(() => {
    // Build changes array: only rows that differ from baseline or are new
    const changes = rows
      .filter((r) => {
        if (r.remove) return true;
        if (!r.assignmentId) return true; // new row
        // Check if modified
        const orig = initialRows.find((ir) => ir.key === r.key);
        if (!orig) return true;
        return (
          r.resourceId !== orig.resourceId ||
          r.roleId !== orig.roleId ||
          r.startDate !== orig.startDate ||
          r.endDate !== orig.endDate ||
          r.hoursPerDay !== orig.hoursPerDay
        );
      })
      .map((r) => ({
        assignmentId: r.assignmentId,
        resourceId: r.resourceId || undefined,
        roleId: r.roleId || undefined,
        startDate: new Date(r.startDate),
        endDate: new Date(r.endDate),
        hoursPerDay: r.hoursPerDay,
        remove: r.remove,
      }));

    if (changes.length === 0) return;

    simulateMut.mutate({ projectId, changes });
  }, [rows, initialRows, projectId, simulateMut]);

  // ── Apply ────────────────────────────────────────────────────────────────

  const applyScenario = useCallback(() => {
    const changes = rows
      .filter((r) => {
        if (r.remove) return true;
        if (!r.assignmentId) return true;
        const orig = initialRows.find((ir) => ir.key === r.key);
        if (!orig) return true;
        return (
          r.resourceId !== orig.resourceId ||
          r.roleId !== orig.roleId ||
          r.startDate !== orig.startDate ||
          r.endDate !== orig.endDate ||
          r.hoursPerDay !== orig.hoursPerDay
        );
      })
      .map((r) => ({
        assignmentId: r.assignmentId,
        resourceId: r.resourceId || undefined,
        roleId: r.roleId || undefined,
        startDate: new Date(r.startDate),
        endDate: new Date(r.endDate),
        hoursPerDay: r.hoursPerDay,
        remove: r.remove,
      }));

    applyMut.mutate(
      { projectId, changes },
      {
        onSuccess: () => {
          setShowApplyConfirm(false);
          // Reload page to see updated state
          window.location.href = `/projects/${projectId}`;
        },
      },
    );
  }, [rows, initialRows, projectId, applyMut]);

  const result = simulateMut.data;
  const activeRows = rows.filter((r) => !r.remove);
  const removedRows = rows.filter((r) => r.remove);

  return (
    <div className="space-y-6">
      {/* Two-panel layout */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        {/* Left: Baseline (read-only) */}
        <div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 p-5">
          <h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-1">
            Current Baseline
          </h2>
          <p className="text-xs text-gray-500 mb-4">
            {baseline.assignments.length} assignment(s) &middot;{" "}
            {formatMoney(baseline.totalCostCents)} total &middot;{" "}
            {baseline.totalHours.toFixed(0)}h
          </p>

          {baseline.assignments.length === 0 ? (
            <p className="text-sm text-gray-400 italic">No assignments yet.</p>
          ) : (
            <div className="space-y-2 max-h-[500px] overflow-y-auto">
              {baseline.assignments.map((a) => (
                <div
                  key={a.id}
                  className="flex items-center justify-between rounded-lg border border-gray-100 dark:border-gray-700 px-3 py-2 text-sm"
                >
                  <div className="min-w-0">
                    <div className="font-medium text-gray-900 dark:text-gray-100 truncate">
                      {a.resourceName}
                      {a.roleName && (
                        <span
                          className="ml-2 inline-block px-1.5 py-0.5 text-xs rounded"
                          style={{
                            backgroundColor: a.roleColor ? `${a.roleColor}20` : "#f3f4f6",
                            color: a.roleColor ?? "#6b7280",
                          }}
                        >
                          {a.roleName}
                        </span>
                      )}
                    </div>
                    <div className="text-xs text-gray-500 mt-0.5">
                      {formatDate(a.startDate)} - {formatDate(a.endDate)} &middot;{" "}
                      {a.hoursPerDay}h/d &middot; {a.workingDays} days
                    </div>
                  </div>
                  <div className="text-right flex-shrink-0 ml-3">
                    <div className="font-mono text-sm text-gray-900 dark:text-gray-100">
                      {formatMoney(a.costCents)}
                    </div>
                    <div className="text-xs text-gray-500">{a.totalHours.toFixed(0)}h</div>
                  </div>
                </div>
              ))}
            </div>
          )}

          {baseline.demands.length > 0 && (
            <div className="mt-4 pt-3 border-t border-gray-100 dark:border-gray-700">
              <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
                Open Demands
              </h3>
              <div className="space-y-1">
                {baseline.demands.map((d) => (
                  <div key={d.id} className="text-xs text-gray-500 flex items-center gap-2">
                    <span
                      className="inline-block w-2 h-2 rounded-full"
                      style={{ backgroundColor: d.roleColor ?? "#9ca3af" }}
                    />
                    {d.roleName || "Unspecified"} &middot; {d.headcount}x &middot;{" "}
                    {d.hoursPerDay}h/d
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>

        {/* Right: Scenario Editor */}
        <div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 p-5">
          <div className="flex items-center justify-between mb-4">
            <div>
              <h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
                Scenario Editor
              </h2>
              <p className="text-xs text-gray-500">
                {activeRows.length} allocation(s)
                {removedRows.length > 0 && (
                  <span className="text-red-500 ml-1">
                    ({removedRows.length} removed)
                  </span>
                )}
              </p>
            </div>
            <div className="flex items-center gap-2">
              {isDirty && (
                <button
                  type="button"
                  onClick={resetScenario}
                  className="text-xs text-gray-500 hover:text-gray-700 underline"
                >
                  Reset
                </button>
              )}
              <button
                type="button"
                onClick={addRow}
                className="inline-flex items-center gap-1 rounded-lg bg-brand-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-brand-700 transition"
              >
                <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
                </svg>
                Add Resource
              </button>
            </div>
          </div>

          <div className="space-y-3 max-h-[500px] overflow-y-auto">
            {rows.map((row) => (
              <ScenarioRowEditor
                key={row.key}
                row={row}
                resources={resources}
                roles={roles}
                resourceMap={resourceMap}
                roleMap={roleMap}
                onUpdate={updateRow}
                onRemove={removeRow}
                onRestore={restoreRow}
              />
            ))}

            {rows.length === 0 && (
              <p className="text-sm text-gray-400 italic text-center py-6">
                Add resources to build your scenario.
              </p>
            )}
          </div>

          {/* Action buttons */}
          <div className="mt-4 pt-3 border-t border-gray-100 dark:border-gray-700 flex items-center gap-3">
            <button
              type="button"
              onClick={runSimulation}
              disabled={!isDirty || simulateMut.isPending}
              className="inline-flex items-center gap-2 rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
            >
              {simulateMut.isPending ? (
                <svg className="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
                </svg>
              ) : (
                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
                </svg>
              )}
              Simulate
            </button>

            {result && (
              <button
                type="button"
                onClick={() => setShowApplyConfirm(true)}
                disabled={applyMut.isPending}
                className="inline-flex items-center gap-2 rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
              >
                Apply Scenario
              </button>
            )}
          </div>

          {simulateMut.error && (
            <p className="mt-2 text-sm text-red-600">{simulateMut.error.message}</p>
          )}
        </div>
      </div>

      {/* Impact Summary */}
      {result && <ImpactSummary result={result} budgetCents={baseline.budgetCents ?? 0} />}

      {/* Apply confirmation dialog */}
      {showApplyConfirm && (
        <ConfirmDialog
          title="Apply Scenario"
          message="This will create/modify real assignments based on your scenario. Existing assignments may be changed or cancelled. This action cannot be undone."
          confirmLabel={applyMut.isPending ? "Applying..." : "Apply"}
          onConfirm={applyScenario}
          onCancel={() => setShowApplyConfirm(false)}
        />
      )}

      {applyMut.isSuccess && (
        <div className="rounded-lg bg-green-50 border border-green-200 p-4 text-sm text-green-800">
          Scenario applied successfully. Redirecting...
        </div>
      )}
    </div>
  );
}

// ── ScenarioRowEditor ────────────────────────────────────────────────────────

interface ScenarioRowEditorProps {
  row: ScenarioRow;
  resources: ResourceOption[];
  roles: RoleOption[];
  resourceMap: Map<string, ResourceOption>;
  roleMap: Map<string, RoleOption>;
  onUpdate: (key: string, updates: Partial<ScenarioRow>) => void;
  onRemove: (key: string) => void;
  onRestore: (key: string) => void;
}

function ScenarioRowEditor({
  row,
  resources,
  roles,
  resourceMap,
  roleMap,
  onUpdate,
  onRemove,
  onRestore,
}: ScenarioRowEditorProps) {
  const isRemoved = row.remove;
  const resource = row.resourceId ? resourceMap.get(row.resourceId) : null;
  const lcrDisplay = resource ? `${formatMoney(resource.lcrCents)}/h` : "";

  return (
    <div
      className={`rounded-lg border p-3 transition ${
        isRemoved
          ? "border-red-200 bg-red-50/50 dark:border-red-800 dark:bg-red-900/10 opacity-60"
          : row.assignmentId
            ? "border-gray-200 dark:border-gray-700"
            : "border-blue-200 bg-blue-50/30 dark:border-blue-800 dark:bg-blue-900/10"
      }`}
    >
      {isRemoved ? (
        <div className="flex items-center justify-between">
          <span className="text-sm text-red-600 line-through">
            {resource?.displayName ?? "Unknown"} &mdash; removed
          </span>
          <button
            type="button"
            onClick={() => onRestore(row.key)}
            className="text-xs text-blue-600 hover:text-blue-800 underline"
          >
            Restore
          </button>
        </div>
      ) : (
        <div className="space-y-2">
          {/* Top row: resource + role + remove */}
          <div className="flex items-center gap-2">
            <select
              value={row.resourceId}
              onChange={(e) => onUpdate(row.key, { resourceId: e.target.value })}
              className="flex-1 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 px-2 py-1.5 text-sm text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-brand-500 focus:border-transparent"
            >
              <option value="">Select resource...</option>
              {resources.map((r) => (
                <option key={r.id} value={r.id}>
                  {r.displayName} ({r.eid})
                </option>
              ))}
            </select>

            <select
              value={row.roleId}
              onChange={(e) => onUpdate(row.key, { roleId: e.target.value })}
              className="w-40 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 px-2 py-1.5 text-sm text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-brand-500 focus:border-transparent"
            >
              <option value="">Role...</option>
              {roles.map((r) => (
                <option key={r.id} value={r.id}>
                  {r.name}
                </option>
              ))}
            </select>

            <button
              type="button"
              onClick={() => onRemove(row.key)}
              className="p-1.5 text-gray-400 hover:text-red-500 transition rounded"
              title="Remove from scenario"
            >
              <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
              </svg>
            </button>
          </div>

          {/* Bottom row: dates + hours + LCR info */}
          <div className="flex items-center gap-2 flex-wrap">
            <div className="flex items-center gap-1">
              <label className="text-xs text-gray-500 whitespace-nowrap">From</label>
              <DateInput
                value={row.startDate}
                onChange={(v) => onUpdate(row.key, { startDate: v })}
                className="w-28 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 px-2 py-1 text-xs text-gray-900 dark:text-gray-100"
              />
            </div>
            <div className="flex items-center gap-1">
              <label className="text-xs text-gray-500 whitespace-nowrap">To</label>
              <DateInput
                value={row.endDate}
                onChange={(v) => onUpdate(row.key, { endDate: v })}
                className="w-28 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 px-2 py-1 text-xs text-gray-900 dark:text-gray-100"
              />
            </div>
            <div className="flex items-center gap-1">
              <label className="text-xs text-gray-500 whitespace-nowrap">h/day</label>
              <input
                type="number"
                min={0}
                max={24}
                step={0.5}
                value={row.hoursPerDay}
                onChange={(e) => onUpdate(row.key, { hoursPerDay: parseFloat(e.target.value) || 0 })}
                className="w-16 rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 px-2 py-1 text-xs text-gray-900 dark:text-gray-100 text-center"
              />
            </div>
            {lcrDisplay && (
              <span className="text-xs text-gray-400 ml-auto">{lcrDisplay}</span>
            )}
            {!row.assignmentId && (
              <span className="text-xs text-blue-500 font-medium">NEW</span>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

// ── ImpactSummary ────────────────────────────────────────────────────────────

interface SimulationResult {
  baseline: { totalCostCents: number; totalHours: number; headcount: number; skillCount: number };
  scenario: { totalCostCents: number; totalHours: number; headcount: number; skillCount: number };
  delta: { costCents: number; hours: number; headcount: number; skillCoveragePct: number };
  resourceImpacts: Array<{
    resourceId: string;
    resourceName: string;
    chargeabilityTarget: number;
    currentUtilization: number;
    scenarioUtilization: number;
    utilizationDelta: number;
    isOverallocated: boolean;
  }>;
  warnings: string[];
  budgetCents: number;
}

function ImpactSummary({ result, budgetCents }: { result: SimulationResult; budgetCents: number }) {
  const { baseline, scenario, delta, resourceImpacts, warnings } = result;

  const costSign = delta.costCents > 0 ? "+" : "";
  const hoursSign = delta.hours > 0 ? "+" : "";
  const headcountSign = delta.headcount > 0 ? "+" : "";

  const costColor = delta.costCents > 0 ? "text-red-600" : delta.costCents < 0 ? "text-green-600" : "text-gray-500";
  const hoursColor = delta.hours > 0 ? "text-amber-600" : delta.hours < 0 ? "text-blue-600" : "text-gray-500";

  const budgetUsedPct = budgetCents > 0 ? Math.round((scenario.totalCostCents / budgetCents) * 100) : null;

  return (
    <div className="space-y-4">
      {/* Delta cards */}
      <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
        <DeltaCard
          label="Cost Impact"
          value={`${costSign}${formatMoney(delta.costCents)}`}
          subtitle={`${formatMoney(scenario.totalCostCents)} total`}
          color={costColor}
        />
        <DeltaCard
          label="Hours Impact"
          value={`${hoursSign}${delta.hours.toFixed(0)}h`}
          subtitle={`${scenario.totalHours.toFixed(0)}h total`}
          color={hoursColor}
        />
        <DeltaCard
          label="Headcount"
          value={`${headcountSign}${delta.headcount}`}
          subtitle={`${scenario.headcount} total`}
          color={delta.headcount !== 0 ? "text-indigo-600" : "text-gray-500"}
        />
        <DeltaCard
          label="Skill Coverage"
          value={`${delta.skillCoveragePct}%`}
          subtitle={`${scenario.skillCount} unique skills`}
          color={delta.skillCoveragePct >= 100 ? "text-green-600" : "text-amber-600"}
        />
      </div>

      {/* Budget progress */}
      {budgetUsedPct !== null && (
        <div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 p-4">
          <div className="flex items-center justify-between text-sm mb-2">
            <span className="text-gray-600 dark:text-gray-400">Budget Usage</span>
            <span className={`font-medium ${budgetUsedPct > 100 ? "text-red-600" : "text-gray-900 dark:text-gray-100"}`}>
              {budgetUsedPct}% of {formatMoney(budgetCents)}
            </span>
          </div>
          <div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
            <div
              className={`h-2 rounded-full transition-all ${
                budgetUsedPct > 100 ? "bg-red-500" : budgetUsedPct > 80 ? "bg-amber-500" : "bg-green-500"
              }`}
              style={{ width: `${Math.min(budgetUsedPct, 100)}%` }}
            />
          </div>
        </div>
      )}

      {/* Warnings */}
      {warnings.length > 0 && (
        <div className="rounded-lg border border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-900/20 p-4">
          <h3 className="text-sm font-medium text-amber-800 dark:text-amber-200 mb-2">Warnings</h3>
          <ul className="space-y-1">
            {warnings.map((w, i) => (
              <li key={i} className="text-sm text-amber-700 dark:text-amber-300 flex items-start gap-2">
                <svg className="w-4 h-4 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
                  <path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
                </svg>
                {w}
              </li>
            ))}
          </ul>
        </div>
      )}

      {/* Resource utilization impacts */}
      {resourceImpacts.length > 0 && (
        <div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 p-4">
          <h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3">
            Resource Utilization Impact
          </h3>
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="text-xs text-gray-500 border-b border-gray-100 dark:border-gray-700">
                  <th className="text-left py-2 pr-4 font-medium">Resource</th>
                  <th className="text-right py-2 px-3 font-medium">Current</th>
                  <th className="text-right py-2 px-3 font-medium">Scenario</th>
                  <th className="text-right py-2 px-3 font-medium">Delta</th>
                  <th className="text-right py-2 pl-3 font-medium">Target</th>
                </tr>
              </thead>
              <tbody>
                {resourceImpacts.map((ri) => (
                  <tr
                    key={ri.resourceId}
                    className={`border-b border-gray-50 dark:border-gray-800 ${
                      ri.isOverallocated ? "bg-red-50/50 dark:bg-red-900/10" : ""
                    }`}
                  >
                    <td className="py-2 pr-4 font-medium text-gray-900 dark:text-gray-100">
                      {ri.resourceName}
                      {ri.isOverallocated && (
                        <span className="ml-2 text-xs text-red-500 font-normal">over-allocated</span>
                      )}
                    </td>
                    <td className="text-right py-2 px-3 text-gray-600 dark:text-gray-400">
                      {ri.currentUtilization.toFixed(1)}%
                    </td>
                    <td className={`text-right py-2 px-3 font-medium ${ri.isOverallocated ? "text-red-600" : "text-gray-900 dark:text-gray-100"}`}>
                      {ri.scenarioUtilization.toFixed(1)}%
                    </td>
                    <td className={`text-right py-2 px-3 ${
                      ri.utilizationDelta > 0 ? "text-amber-600" : ri.utilizationDelta < 0 ? "text-blue-600" : "text-gray-500"
                    }`}>
                      {ri.utilizationDelta > 0 ? "+" : ""}{ri.utilizationDelta.toFixed(1)}%
                    </td>
                    <td className="text-right py-2 pl-3 text-gray-500">
                      {ri.chargeabilityTarget}%
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </div>
  );
}

// ── DeltaCard ────────────────────────────────────────────────────────────────

function DeltaCard({
  label,
  value,
  subtitle,
  color,
}: {
  label: string;
  value: string;
  subtitle: string;
  color: string;
}) {
  return (
    <div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 p-4">
      <p className="text-xs text-gray-500 mb-1">{label}</p>
      <p className={`text-xl font-bold ${color}`}>{value}</p>
      <p className="text-xs text-gray-400 mt-1">{subtitle}</p>
    </div>
  );
}
