"use client";

import { useState } from "react";
import { useQueries } from "@tanstack/react-query";
import { X } from "lucide-react";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/app/shadcn_components/ui/popover";
import { sapToEpc } from "@/app/utils";
import { pickBestIndex, countBelowBand } from "@/lib/reporting/model";
import { EpcChip, moneyFull } from "../components/primitives";

interface ScenarioMeta {
  id: number;
  name: string;
  goal?: string;
  goalValue?: string | null;
  budget?: number | null;
}

interface Baseline {
  avgSap: number;
  totalCarbon: number;
  totalBills: number;
  belowC: number;
}

/** A comparable metric row: how to read each scenario's answer and which way is better. */
interface RowSpec {
  label: string;
  group: string;
  direction: "lower" | "higher" | null;
  value: (m: ScenarioMetrics, b: Baseline) => number | null;
  render: (v: number | null) => React.ReactNode;
}

interface ScenarioMetrics {
  avg_sap: string;
  scenario_epc_counts: Record<string, number>;
  n_units_upgraded: number;
  total_carbon: number;
  total_bills: number;
  construction_cost: number;
  pc_cost: number;
  contingency: number;
  gross_cost: number;
  total_funding: number;
  net_cost: number;
  total_sap_uplift: number;
}

const ROWS: RowSpec[] = [
  {
    group: "Outcome",
    label: "Average EPC after",
    direction: "higher",
    value: (m) => Number(m.avg_sap),
    render: (v) =>
      v === null ? "—" : (
        <span className="inline-flex items-center gap-1.5">
          <EpcChip band={sapToEpc(v)} size="sm" /> {Math.round(v)}
        </span>
      ),
  },
  {
    group: "Outcome",
    label: "Homes below C after",
    direction: "lower",
    value: (m) => countBelowBand(m.scenario_epc_counts, "C"),
    render: (v) => (v === null ? "—" : v.toLocaleString("en-GB")),
  },
  {
    group: "Outcome",
    label: "Homes upgraded",
    direction: "higher",
    value: (m) => m.n_units_upgraded,
    render: (v) => (v === null ? "—" : v.toLocaleString("en-GB")),
  },
  {
    group: "Outcome",
    label: "CO₂ saved /yr",
    direction: "higher",
    value: (m, b) => b.totalCarbon - m.total_carbon,
    render: (v) => (v === null ? "—" : `${Math.round(v)} t`),
  },
  {
    group: "Outcome",
    label: "Bill savings /yr",
    direction: "higher",
    value: (m, b) => b.totalBills - m.total_bills,
    render: (v) => (v === null ? "—" : moneyFull(v)),
  },
  {
    group: "Investment",
    label: "Gross cost",
    direction: "lower",
    value: (m) => m.gross_cost,
    render: (v) => (v === null ? "—" : moneyFull(v)),
  },
  {
    group: "Investment",
    label: "Funding secured",
    direction: "higher",
    value: (m) => m.total_funding,
    render: (v) => (v === null ? "—" : moneyFull(v)),
  },
  {
    group: "Investment",
    label: "Net cost",
    direction: "lower",
    value: (m) => m.net_cost,
    render: (v) => (v === null ? "—" : moneyFull(v)),
  },
  {
    group: "Value for money",
    label: "Cost per SAP point",
    direction: "lower",
    value: (m) =>
      m.total_sap_uplift > 0
        ? (m.construction_cost + m.pc_cost) / m.total_sap_uplift
        : null,
    render: (v) => (v === null ? "—" : moneyFull(v)),
  },
  {
    group: "Value for money",
    label: "Cost per tCO₂/yr",
    direction: "lower",
    value: (m, b) => {
      const saved = b.totalCarbon - m.total_carbon;
      return saved > 0 ? (m.construction_cost + m.pc_cost) / saved : null;
    },
    render: (v) => (v === null ? "—" : moneyFull(v)),
  },
];

export function CompareClientArea({
  portfolioId,
  scenarios,
  baseline,
}: {
  portfolioId: number;
  scenarios: ScenarioMeta[];
  baseline: Baseline;
}) {
  // Up to four columns stay readable at desk widths; the user picks which.
  const MAX_COLUMNS = 4;
  const [selected, setSelected] = useState(() =>
    scenarios.slice(0, MAX_COLUMNS).map((s) => s.id),
  );
  // Column order follows selection order, not the scenario list order.
  const columns = selected
    .map((id) => scenarios.find((s) => s.id === id))
    .filter((s): s is ScenarioMeta => Boolean(s));
  const available = scenarios.filter((s) => !selected.includes(s.id));
  const canAdd = selected.length < MAX_COLUMNS && available.length > 0;

  const addColumn = (id: number) =>
    setSelected((ids) =>
      ids.length < MAX_COLUMNS && !ids.includes(id) ? [...ids, id] : ids,
    );
  const removeColumn = (id: number) =>
    setSelected((ids) => (ids.length > 1 ? ids.filter((x) => x !== id) : ids));

  const results = useQueries({
    queries: columns.map((s) => ({
      queryKey: ["compare-metrics", portfolioId, s.id],
      queryFn: () =>
        fetch(
          `/api/portfolio/${portfolioId}/scenario/${s.id}/metrics`,
        ).then((r) => {
          if (!r.ok) throw new Error("Failed to load scenario");
          return r.json() as Promise<ScenarioMetrics>;
        }),
      refetchOnWindowFocus: false,
    })),
  });

  const loading = results.some((r) => r.isLoading);

  const groups = Array.from(new Set(ROWS.map((r) => r.group)));

  return (
    <div className="space-y-4" data-reporting>
      <div className="flex items-end justify-between gap-4">
        <div>
          <div className="text-[0.74rem] text-gray-600">
            Portfolios / Reporting
          </div>
          <h1 className="mt-0.5 text-[1.35rem] font-semibold tracking-tight text-brandblue">
            Compare scenarios
          </h1>
        </div>
        <div className="flex items-center gap-2">
          <Popover>
            <PopoverTrigger asChild>
              <button
                type="button"
                disabled={!canAdd}
                aria-haspopup="listbox"
                className="inline-flex h-8 items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-3.5 text-sm font-medium text-brandblue disabled:cursor-not-allowed disabled:text-gray-400"
              >
                + Add scenario
              </button>
            </PopoverTrigger>
            <PopoverContent align="end" className="w-72 p-0">
              <div role="listbox" aria-label="Add a scenario to compare" className="max-h-80 overflow-y-auto">
                {available.map((s) => (
                  <button
                    key={s.id}
                    type="button"
                    role="option"
                    aria-selected={false}
                    onClick={() => addColumn(s.id)}
                    className="flex w-full flex-col border-t border-gray-100 px-3.5 py-2.5 text-left first:border-t-0 hover:bg-gray-50"
                  >
                    <span className="text-sm font-semibold text-brandblue">
                      {s.name}
                    </span>
                    <span className="text-[0.7rem] text-gray-600">
                      {s.goal === "Increasing EPC" && s.goalValue
                        ? `Target EPC ${s.goalValue}`
                        : s.goal}
                    </span>
                  </button>
                ))}
                {available.length === 0 && (
                  <p className="px-3.5 py-3 text-[0.78rem] text-gray-600">
                    All scenarios are already shown.
                  </p>
                )}
              </div>
            </PopoverContent>
          </Popover>
          <a
            href={`/portfolio/${portfolioId}/reporting`}
            className="inline-flex h-8 items-center rounded-lg border border-gray-200 bg-white px-3.5 text-sm font-medium"
          >
            ← Back to reporting
          </a>
        </div>
      </div>

      <div className="overflow-x-auto rounded-lg border border-gray-200 bg-white">
        <table className="w-full text-[0.84rem]">
          <thead>
            <tr>
              <th className="w-[22%] px-4 py-4 text-left" />
              <th className="px-4 py-4 text-right align-bottom">
                <span className="text-[0.86rem] font-semibold text-brandblue">
                  Current stock
                </span>
                <span className="block text-[0.68rem] font-normal text-gray-600">
                  No scenario applied
                </span>
              </th>
              {columns.map((s) => (
                <th key={s.id} className="px-4 py-4 text-right align-bottom">
                  <span className="flex items-start justify-end gap-1.5">
                    <span className="text-[0.86rem] font-semibold text-brandblue">
                      {s.name}
                    </span>
                    {columns.length > 1 && (
                      <button
                        type="button"
                        onClick={() => removeColumn(s.id)}
                        aria-label={`Remove ${s.name} from comparison`}
                        className="mt-0.5 text-gray-400 hover:text-gray-700"
                      >
                        <X className="h-3.5 w-3.5" />
                      </button>
                    )}
                  </span>
                  <span className="block text-[0.68rem] font-normal text-gray-600">
                    {s.goal === "Increasing EPC" && s.goalValue
                      ? `Target EPC ${s.goalValue}`
                      : s.goal}
                    {s.budget ? ` · £${(s.budget / 1000).toFixed(0)}k/home` : ""}
                  </span>
                  <a
                    href={`/portfolio/${portfolioId}/reporting?scenario=${s.id}`}
                    className="mt-1 block text-[0.7rem] font-medium text-midblue"
                  >
                    View →
                  </a>
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr>
                <td
                  colSpan={columns.length + 2}
                  className="px-4 py-10 text-center text-sm text-gray-600"
                >
                  Loading scenarios…
                </td>
              </tr>
            ) : (
              groups.map((group) => (
                <GroupRows
                  key={group}
                  group={group}
                  columns={columns.length}
                  results={results.map((r) => r.data as ScenarioMetrics)}
                  baseline={baseline}
                />
              ))
            )}
          </tbody>
        </table>
      </div>
      <p className="mt-2.5 text-[0.75rem] text-gray-600">
        The <span className="font-semibold text-[#0c6b4a]">Best</span> tag marks
        the best value in each row — no overall winner is crowned; trade-offs
        stay visible.
      </p>
    </div>
  );
}

function GroupRows({
  group,
  columns,
  results,
  baseline,
}: {
  group: string;
  columns: number;
  results: ScenarioMetrics[];
  baseline: Baseline;
}) {
  const rows = ROWS.filter((r) => r.group === group);
  return (
    <>
      <tr>
        <td
          colSpan={columns + 2}
          className="px-4 pb-1.5 pt-4 text-[0.66rem] font-bold uppercase tracking-wide text-[#a07c42]"
        >
          {group}
        </td>
      </tr>
      {rows.map((row) => {
        const scenarioValues = results.map((m) =>
          m ? row.value(m, baseline) : null,
        );
        const best =
          row.direction === null
            ? null
            : pickBestIndex(scenarioValues, row.direction);
        // "before" cell: baseline has no scenario metric, so most rows show —.
        const baselineCell =
          row.label === "Average EPC after"
            ? row.render(baseline.avgSap)
            : row.label === "Homes below C after"
              ? baseline.belowC.toLocaleString("en-GB")
              : "—";
        return (
          <tr key={row.label} className="border-t border-gray-100">
            <td className="px-4 py-2.5 text-left text-gray-500">{row.label}</td>
            <td className="px-4 py-2.5 text-right tabular-nums text-gray-900">
              {baselineCell}
            </td>
            {scenarioValues.map((v, i) => (
              <td
                key={i}
                className={`px-4 py-2.5 text-right tabular-nums ${
                  best === i ? "font-bold text-[#0c6b4a]" : "text-gray-900"
                }`}
              >
                {best === i && (
                  <span className="mr-1.5 inline-flex items-center rounded bg-[#e9f4ef] px-1.5 py-0.5 align-middle text-[0.6rem] font-bold uppercase tracking-wide text-[#0c6b4a]">
                    Best
                  </span>
                )}
                {row.render(v)}
              </td>
            ))}
          </tr>
        );
      })}
    </>
  );
}
