/**
 * 账户树与报表计算（plan.md「5.1 账户树与报表」）。
 */

import { addDecimals, compareDecimals, negateDecimal } from '../core/decimal';
import { computeAccountBalances } from '../core/ledger';
import type { Account, LedgerIndex, Transaction } from '../core/types';

export interface AccountNode {
  name: string;
  fullName: string;
  balance: string;
  children: AccountNode[];
  depth: number;
}

/** 构建账户树（按冒号分层）。 */
export function buildAccountTree(
  accounts: Map<string, Account>,
  transactions: Transaction[],
  ledger?: LedgerIndex,
): AccountNode[] {
  // 计算每个账户余额
  const balances = computeAccountBalances(ledger ?? { files: [], accounts, transactions, balances: [], options: [], diagnostics: [], unsupported: [] });

  // 按顶层类型分组（Assets/Liabilities/Income/Expenses/Equity）
  const roots: AccountNode[] = [];
  const topLevel = new Set<string>();
  for (const name of accounts.keys()) {
    topLevel.add(name.split(':')[0]);
  }

  for (const root of [...topLevel].sort()) {
    const rootAccounts = [...accounts.keys()].filter(a => a.startsWith(root + ':') || a === root);
    roots.push(buildNode(root, root, rootAccounts, balances, 0));
  }
  return roots;
}

function buildNode(
  segment: string,
  fullName: string,
  allAccounts: string[],
  balances: Map<string, string>,
  depth: number,
): AccountNode {
  const directBalance = balances.get(fullName) ?? '0';
  // 子账户 = 全名以 fullName: 开头的下一层
  const childPrefix = fullName + ':';
  const childSegments = new Set<string>();
  for (const a of allAccounts) {
    if (a.startsWith(childPrefix)) {
      const rest = a.slice(childPrefix.length);
      const nextSeg = rest.split(':')[0];
      childSegments.add(nextSeg);
    }
  }
  const children = [...childSegments].sort().map(seg =>
    buildNode(seg, `${fullName}:${seg}`, allAccounts, balances, depth + 1)
  );
  return { name: segment, fullName, balance: directBalance, children, depth };
}

/** 计算账户总余额（含子账户）。 */
export function calculateAccountTotalBalance(node: AccountNode): string {
  const childSum = node.children.reduce((sum, c) => {
    return addDecimals([sum, calculateAccountTotalBalance(c)]);
  }, '0');
  return addDecimals([node.balance, childSum]);
}

/** 报表计算。 */
export interface LedgerReport {
  income: string;
  expense: string;
  netIncome: string;
  assets: string;
  liabilities: string;
  netWorth: string;
}

export function calculateReport(
  ledger: LedgerIndex,
  periodStart?: string,
  periodEnd?: string,
): LedgerReport {
  let tx = ledger.transactions;
  if (periodStart && periodEnd) {
    tx = tx.filter(t => {
      const d = t.date.slice(0, 10);
      return d >= periodStart && d <= periodEnd;
    });
  }

  const incomeAmounts: string[] = [];
  const expenseAmounts: string[] = [];
  const assetAmounts: string[] = [];
  const liabilityAmounts: string[] = [];

  for (const t of tx) {
    for (const p of t.postings) {
      if (!p.amount) continue;
      if (p.account.startsWith('Income')) {
        incomeAmounts.push(negateDecimal(p.amount));
      }
      if (p.account.startsWith('Expenses')) {
        expenseAmounts.push(p.amount);
      }
      if (p.account.startsWith('Assets')) {
        assetAmounts.push(p.amount);
      }
      if (p.account.startsWith('Liabilities')) {
        liabilityAmounts.push(p.amount);
      }
    }
  }

  const income = addDecimals(incomeAmounts.length ? incomeAmounts : ['0']);
  const expense = addDecimals(expenseAmounts.length ? expenseAmounts : ['0']);
  const assets = addDecimals(assetAmounts.length ? assetAmounts : ['0']);
  const liabilitiesSum = addDecimals(liabilityAmounts.length ? liabilityAmounts : ['0']);

  // Beancount 复式记账中 Liabilities 账户正常余额为负数（与 Assets 相反）。
  // liabilitiesSum 保持原始符号，用于 netWorth = assets + liabilitiesSum 的正确计算。
  // liabilities 字段取绝对值供 UI 展示（用户看到的负债是正数）。
  const liabilities = compareDecimals(liabilitiesSum, '0') < 0 ? negateDecimal(liabilitiesSum) : liabilitiesSum;
  const netWorth = addDecimals([assets, liabilitiesSum]);

  return {
    income,
    expense,
    netIncome: addDecimals([income, negateDecimal(expense)]),
    assets,
    liabilities,
    netWorth,
  };
}
