import { Fragment, useState, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { ArrowUpDown } from "lucide-react";
import type { PivotConfig, PivotResult, PivotResultRow } from "../../shared/types";

const cadFormatter = (value: number) =>
  new Intl.NumberFormat("en-CA", { style: "currency", currency: "CAD", maximumFractionDigits: 0 }).format(value);

const STORAGE_KEY = "pivot-subtotals-position";

interface DynamicReportTableProps {
  config: PivotConfig;
  result: PivotResult;
}

/** A pivoted row: one per unique combination of row dimensions */
interface PivotedRow {
  rowKeys: Record<string, string>;             // row-dimension values
  cells: Record<string, Record<string, number>>; // colValue → measure → value
}

/** Pivot raw result rows into one PivotedRow per unique row-key combination */
function pivotRows(
  rows: PivotResultRow[],
  rowDims: string[],
  colDims: string[],
  measures: string[],
): PivotedRow[] {
  const map = new Map<string, PivotedRow>();

  for (const row of rows) {
    const rowKey = rowDims.map((d) => row.keys[d] || "").join("\0");
    let pivoted = map.get(rowKey);
    if (!pivoted) {
      const rowKeys: Record<string, string> = {};
      for (const d of rowDims) rowKeys[d] = row.keys[d] || "";
      pivoted = { rowKeys, cells: {} };
      map.set(rowKey, pivoted);
    }

    const colKey = colDims.length > 0
      ? colDims.map((d) => row.keys[d] || "").join("\0")
      : "__all__";
    if (!pivoted.cells[colKey]) pivoted.cells[colKey] = {};
    for (const m of measures) {
      pivoted.cells[colKey][m] = (pivoted.cells[colKey][m] || 0) + (row.measures[m] || 0);
    }
  }

  return Array.from(map.values());
}

interface GroupNode {
  key: string;
  label: string;
  pivotedRows: PivotedRow[];
  children: GroupNode[];
}

function buildGroups(rows: PivotedRow[], rowDims: string[], depth: number): GroupNode[] {
  if (depth >= rowDims.length) return [];
  const dim = rowDims[depth];
  const map = new Map<string, PivotedRow[]>();
  for (const row of rows) {
    const key = row.rowKeys[dim] || "";
    if (!map.has(key)) map.set(key, []);
    map.get(key)!.push(row);
  }
  const groups: GroupNode[] = [];
  for (const [key, groupRows] of map) {
    groups.push({
      key,
      label: key,
      pivotedRows: groupRows,
      children: buildGroups(groupRows, rowDims, depth + 1),
    });
  }
  return groups;
}

function computeSubtotals(
  rows: PivotedRow[],
  measures: string[],
  colValues: string[],
): Record<string, Record<string, number>> {
  const result: Record<string, Record<string, number>> = {};
  for (const colVal of colValues) {
    result[colVal] = {};
    for (const m of measures) {
      result[colVal][m] = rows.reduce((sum, r) => sum + (r.cells[colVal]?.[m] || 0), 0);
    }
  }
  return result;
}

export default function DynamicReportTable({ config, result }: DynamicReportTableProps) {
  const { t } = useTranslation();
  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;
    });
  };

  const rowDims = config.rows;
  const colDims = config.columns;
  const colValues = colDims.length > 0 ? result.columnValues : ["__all__"];
  const measures = config.values;

  // Display label for a composite column key (joined with \0)
  const colLabel = (compositeKey: string) => compositeKey.split("\0").join(" — ");

  // Pivot the flat SQL rows into one PivotedRow per unique row-key combo
  const pivotedRows = useMemo(
    () => pivotRows(result.rows, rowDims, colDims, measures),
    [result.rows, rowDims, colDims, measures],
  );

  if (pivotedRows.length === 0) {
    return (
      <div className="bg-[var(--card)] border border-[var(--border)] rounded-xl p-8 text-center text-[var(--muted-foreground)]">
        {t("reports.pivot.noData")}
      </div>
    );
  }

  const groups = rowDims.length > 0 ? buildGroups(pivotedRows, rowDims, 0) : [];
  const grandTotals = computeSubtotals(pivotedRows, measures, colValues);

  const fieldLabel = (id: string) => t(`reports.pivot.${id === "level1" ? "level1" : id === "level2" ? "level2" : id === "type" ? "categoryType" : id}`);
  const measureLabel = (id: string) => t(`reports.pivot.${id}`);

  return (
    <div className="bg-[var(--card)] border border-[var(--border)] rounded-xl overflow-hidden">
      {rowDims.length > 1 && (
        <div className="flex justify-end px-3 py-2 border-b border-[var(--border)]">
          <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">
        <table className="w-full text-sm">
          <thead>
            <tr className="border-b border-[var(--border)]">
              {rowDims.map((dim) => (
                <th key={dim} className="text-left px-3 py-2 font-medium text-[var(--muted-foreground)]">
                  {fieldLabel(dim)}
                </th>
              ))}
              {colValues.map((colVal) =>
                measures.map((m) => (
                  <th key={`${colVal}-${m}`} className="text-right px-3 py-2 font-medium text-[var(--muted-foreground)] border-l border-[var(--border)]">
                    {colDims.length > 0 ? (measures.length > 1 ? `${colLabel(colVal)} — ${measureLabel(m)}` : colLabel(colVal)) : measureLabel(m)}
                  </th>
                ))
              )}
            </tr>
          </thead>
          <tbody>
            {rowDims.length === 0 ? (
              <tr className="border-b border-[var(--border)]/50">
                {colValues.map((colVal) =>
                  measures.map((m) => (
                    <td key={`${colVal}-${m}`} className="text-right px-3 py-1.5 border-l border-[var(--border)]/50">
                      {cadFormatter(grandTotals[colVal]?.[m] || 0)}
                    </td>
                  ))
                )}
              </tr>
            ) : (
              groups.map((group) => (
                <GroupRows
                  key={group.key}
                  group={group}
                  colValues={colValues}
                  measures={measures}
                  rowDims={rowDims}
                  depth={0}
                  subtotalsOnTop={subtotalsOnTop}
                />
              ))
            )}
            {/* Grand total */}
            <tr className="border-t-2 border-[var(--border)] font-bold bg-[var(--muted)]/20">
              <td colSpan={rowDims.length || 1} className="px-3 py-2">
                {t("reports.pivot.total")}
              </td>
              {colValues.map((colVal) =>
                measures.map((m) => (
                  <td key={`total-${colVal}-${m}`} className="text-right px-3 py-2 border-l border-[var(--border)]/50">
                    {cadFormatter(grandTotals[colVal]?.[m] || 0)}
                  </td>
                ))
              )}
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  );
}

function GroupRows({
  group,
  colValues,
  measures,
  rowDims,
  depth,
  subtotalsOnTop,
}: {
  group: GroupNode;
  colValues: string[];
  measures: string[];
  rowDims: string[];
  depth: number;
  subtotalsOnTop: boolean;
}) {
  const isLeafLevel = depth === rowDims.length - 1;
  const subtotals = computeSubtotals(group.pivotedRows, measures, colValues);

  const subtotalRow = rowDims.length > 1 && !isLeafLevel ? (
    <tr className="bg-[var(--muted)]/30 font-semibold border-b border-[var(--border)]/50">
      <td className="px-3 py-1.5" style={{ paddingLeft: `${depth * 16 + 12}px` }}>
        {group.label}
      </td>
      {depth < rowDims.length - 1 && <td colSpan={rowDims.length - depth - 1} />}
      {colValues.map((colVal) =>
        measures.map((m) => (
          <td key={`sub-${colVal}-${m}`} className="text-right px-3 py-1.5 border-l border-[var(--border)]/50">
            {cadFormatter(subtotals[colVal]?.[m] || 0)}
          </td>
        ))
      )}
    </tr>
  ) : null;

  if (isLeafLevel) {
    // Render one table row per pivoted row (already deduplicated by row keys)
    return (
      <>
        {group.pivotedRows.map((pRow, i) => (
          <tr key={i} className="border-b border-[var(--border)]/50">
            {rowDims.map((dim, di) => (
              <td
                key={dim}
                className="px-3 py-1.5"
                style={di === 0 ? { paddingLeft: `${depth * 16 + 12}px` } : undefined}
              >
                {pRow.rowKeys[dim] || ""}
              </td>
            ))}
            {colValues.map((colVal) =>
              measures.map((m) => (
                <td key={`${colVal}-${m}`} className="text-right px-3 py-1.5 border-l border-[var(--border)]/50">
                  {cadFormatter(pRow.cells[colVal]?.[m] || 0)}
                </td>
              ))
            )}
          </tr>
        ))}
      </>
    );
  }

  const childContent = group.children.map((child) => (
    <GroupRows
      key={child.key}
      group={child}
      colValues={colValues}
      measures={measures}
      rowDims={rowDims}
      depth={depth + 1}
      subtotalsOnTop={subtotalsOnTop}
    />
  ));

  return (
    <Fragment>
      {subtotalsOnTop && subtotalRow}
      {childContent}
      {!subtotalsOnTop && subtotalRow}
    </Fragment>
  );
}
