import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import { ArrowUpDown, ChevronDown, ChevronRight, ChevronsDownUp, ChevronsUpDown } from "lucide-react";
import type { CategoryDelta } from "../../shared/types";
import { reorderRows } from "../../utils/reorderRows";
import type { CollapseAccessors } from "../../utils/collapsibleRows";
import { useCollapsibleGroups } from "../../hooks/useCollapsibleGroups";
import { type SectionType, type Totals, sumLeaves, pct, computeResults } from "./compareResults";

export interface ComparePeriodTableProps {
  rows: CategoryDelta[];
  /** Label for the "previous" monthly column (e.g. "March 2026" or "2025"). */
  previousLabel: string;
  /** Label for the "current" monthly column (e.g. "April 2026" or "2026"). */
  currentLabel: string;
  /** Optional label for the previous cumulative window (YTD). Falls back to previousLabel. */
  cumulativePreviousLabel?: string;
  /** Optional label for the current cumulative window (YTD). Falls back to currentLabel. */
  cumulativeCurrentLabel?: string;
}

function formatCurrency(amount: number, language: string): string {
  return new Intl.NumberFormat(language === "fr" ? "fr-CA" : "en-CA", {
    style: "currency",
    currency: "CAD",
    maximumFractionDigits: 0,
  }).format(amount);
}

function formatSignedCurrency(amount: number, language: string): string {
  return new Intl.NumberFormat(language === "fr" ? "fr-CA" : "en-CA", {
    style: "currency",
    currency: "CAD",
    maximumFractionDigits: 0,
    signDisplay: "always",
  }).format(amount);
}

function formatPct(pctValue: number | null, language: string): string {
  if (pctValue === null) return "—";
  return new Intl.NumberFormat(language === "fr" ? "fr-CA" : "en-CA", {
    style: "percent",
    maximumFractionDigits: 1,
    signDisplay: "always",
  }).format(pctValue / 100);
}

/**
 * Delta colour, direction-aware (Issue #253). Expenses/transfers keep the
 * spending convention (increase → red, decrease → green); income and the
 * result lines invert it (higher is better → green). Also used to colour a
 * result *amount* by sign: a surplus is green, a deficit red.
 */
function deltaColor(value: number, higherIsBetter: boolean): string {
  if (value === 0) return "";
  const good = higherIsBetter ? value > 0 : value < 0;
  return good ? "var(--positive, #10b981)" : "var(--negative, #ef4444)";
}

const STORAGE_KEY = "compare-subtotals-position";

// Collapse groups keyed by category id; a row is hidden when any ancestor
// (walking parent_id) is collapsed, so every parent level is collapsible.
const COMPARE_COLLAPSE_ACCESSORS: CollapseAccessors<CategoryDelta> = {
  keyOf: (row) => `p:${row.categoryId}`,
  parentKeyOf: (row) => (row.parent_id != null ? `p:${row.parent_id}` : null),
  depthOf: (row) => row.depth ?? 0,
  isParent: (row) => row.is_parent ?? false,
};

const COMPARE_EXPANDED_STORAGE_KEY = "reports-compare-expanded";

const COL_COUNT = 9;

export default function ComparePeriodTable({
  rows,
  previousLabel,
  currentLabel,
  cumulativePreviousLabel,
  cumulativeCurrentLabel,
}: ComparePeriodTableProps) {
  const { t, i18n } = useTranslation();
  const lang = i18n.language;

  const [subtotalsOnTop, setSubtotalsOnTop] = useState(() => {
    const stored = localStorage.getItem(STORAGE_KEY);
    return stored === null ? true : stored === "top";
  });
  const toggleSubtotals = () => {
    setSubtotalsOnTop((prev) => {
      const next = !prev;
      localStorage.setItem(STORAGE_KEY, next ? "top" : "bottom");
      return next;
    });
  };

  // Collapse/expand of sub-category groups — collapsed by default (issue #254).
  const groups = useCollapsibleGroups<CategoryDelta>(
    COMPARE_EXPANDED_STORAGE_KEY,
    COMPARE_COLLAPSE_ACCESSORS,
  );

  const monthPrevLabel = previousLabel;
  const monthCurrLabel = currentLabel;
  const ytdPrevLabel = cumulativePreviousLabel ?? previousLabel;
  const ytdCurrLabel = cumulativeCurrentLabel ?? currentLabel;

  // Group rows into contiguous type sections (the service already type-sorts:
  // income → expense → transfer).
  const sectionLabels: Record<SectionType, string> = {
    expense: t("reports.compare.sections.expenses"),
    income: t("reports.compare.sections.income"),
    transfer: t("reports.compare.sections.transfers"),
  };
  const sectionTotalKeys: Record<SectionType, string> = {
    expense: "reports.compare.totalExpenses",
    income: "reports.compare.totalIncome",
    transfer: "reports.compare.totalTransfers",
  };
  const sections: { type: SectionType; rows: CategoryDelta[] }[] = [];
  let currentType: SectionType | null = null;
  for (const row of rows) {
    const type = (row.category_type ?? "expense") as SectionType;
    if (type !== currentType) {
      currentType = type;
      sections.push({ type, rows: [] });
    }
    sections[sections.length - 1].rows.push(row);
  }

  // Income-statement result lines (Issue #253): revenues − expenses, then the
  // net after transfers. Replaces the old flat grand total, which is meaningless
  // once revenues and (ABS) expenses share one table.
  const results = computeResults(rows);
  const nonTransferSections = sections.filter((s) => s.type !== "transfer");
  const transferSection = sections.find((s) => s.type === "transfer");

  const renderSection = (section: { type: SectionType; rows: CategoryDelta[] }) => {
    // Income section: an increase is good (green); expenses/transfers keep the
    // spending convention (increase → red).
    const higherIsBetter = section.type === "income";
    const sectionTotals = sumLeaves(section.rows);
    return (
      <Fragment key={section.type}>
        <tr className="bg-[var(--muted)]">
          <td
            colSpan={COL_COUNT}
            className="px-3 py-1.5 font-semibold text-[var(--muted-foreground)] uppercase text-xs tracking-wider sticky left-0 bg-[var(--muted)]"
          >
            {sectionLabels[section.type]}
          </td>
        </tr>
        {reorderRows(groups.visible(section.rows), subtotalsOnTop).map((row) => {
          const isParent = row.is_parent ?? false;
          const depth = row.depth ?? 0;
          const isTopParent = isParent && depth === 0;
          const isIntermediateParent = isParent && depth >= 1;
          const collapsed = isParent && groups.isCollapsed(row);
          const paddingClass =
            depth >= 3 ? "pl-20" : depth === 2 ? "pl-14" : depth === 1 ? "pl-8" : "px-3";
          return (
            <tr
              key={`${row.categoryId ?? "uncat"}-${isParent}-${depth}-${row.categoryName}`}
              aria-level={isParent ? depth + 1 : undefined}
              className={`border-b border-[var(--border)]/50 ${
                isTopParent
                  ? "bg-[color-mix(in_srgb,var(--muted)_30%,var(--card))] font-semibold"
                  : isIntermediateParent
                    ? "bg-[color-mix(in_srgb,var(--muted)_15%,var(--card))] font-medium"
                    : "hover:bg-[var(--muted)]/40"
              }`}
            >
              <td
                className={`py-1.5 sticky left-0 z-10 ${
                  isTopParent
                    ? "px-3 bg-[color-mix(in_srgb,var(--muted)_30%,var(--card))]"
                    : isIntermediateParent
                      ? `${paddingClass} bg-[color-mix(in_srgb,var(--muted)_15%,var(--card))]`
                      : `${paddingClass} bg-[var(--card)]`
                }`}
              >
                {isParent ? (
                  <button
                    type="button"
                    onClick={() => groups.toggle(row)}
                    aria-expanded={!collapsed}
                    className="flex items-center gap-2 w-full text-left hover:opacity-80 transition-opacity"
                  >
                    {collapsed ? (
                      <ChevronRight size={14} className="shrink-0 text-[var(--muted-foreground)]" />
                    ) : (
                      <ChevronDown size={14} className="shrink-0 text-[var(--muted-foreground)]" />
                    )}
                    <span
                      className="w-2.5 h-2.5 rounded-full shrink-0"
                      style={{ backgroundColor: row.categoryColor }}
                    />
                    {row.categoryName}
                  </button>
                ) : (
                  <span className="flex items-center gap-2">
                    <span
                      className="w-2.5 h-2.5 rounded-full shrink-0"
                      style={{ backgroundColor: row.categoryColor }}
                    />
                    {row.categoryName}
                  </span>
                )}
              </td>
              {/* Monthly block */}
              <td className="text-right px-3 py-1.5 border-l border-[var(--border)]/50 tabular-nums">
                {formatCurrency(row.currentAmount, lang)}
              </td>
              <td className="text-right px-3 py-1.5 tabular-nums">
                {formatCurrency(row.previousAmount, lang)}
              </td>
              <td
                className="text-right px-3 py-1.5 tabular-nums font-medium"
                style={{ color: deltaColor(row.deltaAbs, higherIsBetter) }}
              >
                {formatSignedCurrency(row.deltaAbs, lang)}
              </td>
              <td
                className="text-right px-3 py-1.5 tabular-nums"
                style={{ color: deltaColor(row.deltaAbs, higherIsBetter) }}
              >
                {formatPct(row.deltaPct, lang)}
              </td>
              {/* Cumulative YTD block */}
              <td className="text-right px-3 py-1.5 border-l border-[var(--border)]/50 tabular-nums">
                {formatCurrency(row.cumulativeCurrentAmount, lang)}
              </td>
              <td className="text-right px-3 py-1.5 tabular-nums">
                {formatCurrency(row.cumulativePreviousAmount, lang)}
              </td>
              <td
                className="text-right px-3 py-1.5 tabular-nums font-medium"
                style={{ color: deltaColor(row.cumulativeDeltaAbs, higherIsBetter) }}
              >
                {formatSignedCurrency(row.cumulativeDeltaAbs, lang)}
              </td>
              <td
                className="text-right px-3 py-1.5 tabular-nums"
                style={{ color: deltaColor(row.cumulativeDeltaAbs, higherIsBetter) }}
              >
                {formatPct(row.cumulativeDeltaPct, lang)}
              </td>
            </tr>
          );
        })}
        {/* Section net total */}
        <tr className="border-b border-[var(--border)] bg-[color-mix(in_srgb,var(--muted)_40%,var(--card))] font-semibold text-sm">
          <td className="px-3 py-2.5 sticky left-0 bg-[color-mix(in_srgb,var(--muted)_40%,var(--card))] z-10">
            {t(sectionTotalKeys[section.type])}
          </td>
          <td className="text-right px-3 py-2.5 border-l border-[var(--border)]/50 tabular-nums">
            {formatCurrency(sectionTotals.monthCurrent, lang)}
          </td>
          <td className="text-right px-3 py-2.5 tabular-nums">
            {formatCurrency(sectionTotals.monthPrevious, lang)}
          </td>
          <td
            className="text-right px-3 py-2.5 tabular-nums"
            style={{ color: deltaColor(sectionTotals.monthDelta, higherIsBetter) }}
          >
            {formatSignedCurrency(sectionTotals.monthDelta, lang)}
          </td>
          <td
            className="text-right px-3 py-2.5 tabular-nums"
            style={{ color: deltaColor(sectionTotals.monthDelta, higherIsBetter) }}
          >
            {formatPct(pct(sectionTotals.monthDelta, sectionTotals.monthPrevious), lang)}
          </td>
          <td className="text-right px-3 py-2.5 border-l border-[var(--border)]/50 tabular-nums">
            {formatCurrency(sectionTotals.ytdCurrent, lang)}
          </td>
          <td className="text-right px-3 py-2.5 tabular-nums">
            {formatCurrency(sectionTotals.ytdPrevious, lang)}
          </td>
          <td
            className="text-right px-3 py-2.5 tabular-nums"
            style={{ color: deltaColor(sectionTotals.ytdDelta, higherIsBetter) }}
          >
            {formatSignedCurrency(sectionTotals.ytdDelta, lang)}
          </td>
          <td
            className="text-right px-3 py-2.5 tabular-nums"
            style={{ color: deltaColor(sectionTotals.ytdDelta, higherIsBetter) }}
          >
            {formatPct(pct(sectionTotals.ytdDelta, sectionTotals.ytdPrevious), lang)}
          </td>
        </tr>
      </Fragment>
    );
  };

  // A result line (before-transfers subtotal or the net total). Higher is always
  // better here: amounts are coloured by sign (surplus green / deficit red) and
  // deltas by improvement.
  const renderResultRow = (labelKey: string, tot: Totals, strong: boolean) => {
    const rowBg = strong
      ? "bg-[color-mix(in_srgb,var(--muted)_20%,var(--card))]"
      : "bg-[color-mix(in_srgb,var(--muted)_10%,var(--card))]";
    const rowClass = strong
      ? `border-t-2 border-[var(--border)] font-bold text-sm ${rowBg}`
      : `border-b border-[var(--border)] font-semibold text-sm ${rowBg}`;
    const cell = "text-right px-3 py-3 tabular-nums";
    return (
      <tr key={labelKey} className={rowClass}>
        <td className={`px-3 py-3 sticky left-0 z-10 ${rowBg}`}>{t(labelKey)}</td>
        <td
          className={`${cell} border-l border-[var(--border)]/50`}
          style={{ color: deltaColor(tot.monthCurrent, true) }}
        >
          {formatCurrency(tot.monthCurrent, lang)}
        </td>
        <td className={cell} style={{ color: deltaColor(tot.monthPrevious, true) }}>
          {formatCurrency(tot.monthPrevious, lang)}
        </td>
        <td className={cell} style={{ color: deltaColor(tot.monthDelta, true) }}>
          {formatSignedCurrency(tot.monthDelta, lang)}
        </td>
        <td className={cell} style={{ color: deltaColor(tot.monthDelta, true) }}>
          {formatPct(pct(tot.monthDelta, tot.monthPrevious), lang)}
        </td>
        <td
          className={`${cell} border-l border-[var(--border)]/50`}
          style={{ color: deltaColor(tot.ytdCurrent, true) }}
        >
          {formatCurrency(tot.ytdCurrent, lang)}
        </td>
        <td className={cell} style={{ color: deltaColor(tot.ytdPrevious, true) }}>
          {formatCurrency(tot.ytdPrevious, lang)}
        </td>
        <td className={cell} style={{ color: deltaColor(tot.ytdDelta, true) }}>
          {formatSignedCurrency(tot.ytdDelta, lang)}
        </td>
        <td className={cell} style={{ color: deltaColor(tot.ytdDelta, true) }}>
          {formatPct(pct(tot.ytdDelta, tot.ytdPrevious), lang)}
        </td>
      </tr>
    );
  };

  const hasGroups = groups.groupCount(rows) > 0;
  const allExpanded = groups.allExpanded(rows);

  return (
    <div className="bg-[var(--card)] border border-[var(--border)] rounded-xl overflow-hidden">
      <div className="flex justify-end items-center gap-1 px-3 py-2 border-b border-[var(--border)]">
        {hasGroups && (
          <button
            type="button"
            onClick={() => (allExpanded ? groups.collapseAll(rows) : groups.expandAll(rows))}
            className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-medium text-[var(--muted-foreground)] hover:bg-[var(--muted)] transition-colors"
          >
            {allExpanded ? <ChevronsDownUp size={13} /> : <ChevronsUpDown size={13} />}
            {allExpanded ? t("reports.collapse.collapseAll") : t("reports.collapse.expandAll")}
          </button>
        )}
        <button
          onClick={toggleSubtotals}
          className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-medium text-[var(--muted-foreground)] hover:bg-[var(--muted)] transition-colors"
        >
          <ArrowUpDown size={13} />
          {subtotalsOnTop ? t("reports.subtotalsOnTop") : t("reports.subtotalsOnBottom")}
        </button>
      </div>
      <div className="overflow-x-auto overflow-y-auto" style={{ maxHeight: "calc(100vh - 220px)" }}>
        <table className="w-full text-sm">
          <thead className="sticky top-0 z-20">
            <tr className="border-b border-[var(--border)] bg-[var(--card)]">
              <th
                rowSpan={2}
                className="text-left px-3 py-2 font-medium text-[var(--muted-foreground)] align-bottom sticky left-0 bg-[var(--card)] z-30 min-w-[180px]"
              >
                {t("reports.highlights.category")}
              </th>
              <th
                colSpan={4}
                className="text-center px-3 py-1 font-medium text-[var(--muted-foreground)] border-l border-[var(--border)] bg-[var(--card)]"
              >
                {t("reports.bva.monthly")}
              </th>
              <th
                colSpan={4}
                className="text-center px-3 py-1 font-medium text-[var(--muted-foreground)] border-l border-[var(--border)] bg-[var(--card)]"
              >
                {t("reports.bva.ytd")}
              </th>
            </tr>
            <tr className="border-b border-[var(--border)] bg-[var(--card)]">
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] border-l border-[var(--border)] bg-[var(--card)]">
                <div>{t("reports.compare.currentAmount")}</div>
                <div className="text-[10px] font-normal opacity-70">{monthCurrLabel}</div>
              </th>
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] bg-[var(--card)]">
                <div>{t("reports.compare.previousAmount")}</div>
                <div className="text-[10px] font-normal opacity-70">{monthPrevLabel}</div>
              </th>
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] bg-[var(--card)]">
                {t("reports.bva.dollarVar")}
              </th>
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] bg-[var(--card)]">
                {t("reports.bva.pctVar")}
              </th>
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] border-l border-[var(--border)] bg-[var(--card)]">
                <div>{t("reports.compare.currentAmount")}</div>
                <div className="text-[10px] font-normal opacity-70">{ytdCurrLabel}</div>
              </th>
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] bg-[var(--card)]">
                <div>{t("reports.compare.previousAmount")}</div>
                <div className="text-[10px] font-normal opacity-70">{ytdPrevLabel}</div>
              </th>
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] bg-[var(--card)]">
                {t("reports.bva.dollarVar")}
              </th>
              <th className="text-right px-3 py-1 font-medium text-[var(--muted-foreground)] bg-[var(--card)]">
                {t("reports.bva.pctVar")}
              </th>
            </tr>
          </thead>
          <tbody>
            {rows.length === 0 ? (
              <tr>
                <td colSpan={COL_COUNT} className="px-3 py-4 text-center text-[var(--muted-foreground)] italic">
                  {t("reports.empty.noData")}
                </td>
              </tr>
            ) : (
              <>
                {nonTransferSections.map(renderSection)}
                {/* Operating result (revenues − expenses), shown before the
                    transfers section only when transfers exist — otherwise it
                    equals the net total below and would just be noise. */}
                {results.hasTransfers &&
                  renderResultRow(
                    "reports.compare.resultBeforeTransfers",
                    results.resultBefore,
                    false,
                  )}
                {transferSection && renderSection(transferSection)}
                {/* Bottom line: result after netting transfers. */}
                {renderResultRow("reports.compare.resultNet", results.resultNet, true)}
              </>
            )}
          </tbody>
        </table>
      </div>
    </div>
  );
}
