import { describe, expect, it } from 'vitest';
import { calculateNetWorth, calculateBalanceByType, calculateNetWorthTrend } from '../src/domain/stats/netWorth';
import { generateAnnualReport } from '../src/domain/stats/annualReport';
import { buildAccountTree, calculateAccountTotalBalance, calculateReport } from '../src/domain/taxonomy/accountTree';
import { parseLedger } from '../src/domain/core/ledger';
import type { Transaction } from '../src/domain/core/types';

const tx = (over: Partial<Transaction>): Transaction => ({
  id: 't1', date: '2026-07-10', flag: '*', postings: [], tags: [], links: [], source: 'mobile.bean', raw: '',
  ...over,
});

const sampleTx: Transaction[] = [
  tx({ id: 't1', date: '2026-01-15', postings: [{ account: 'Assets:Alipay', amount: '-100', currency: 'CNY' }, { account: 'Expenses:Food', amount: '100', currency: 'CNY' }] }),
  tx({ id: 't2', date: '2026-01-20', postings: [{ account: 'Assets:Bank', amount: '5000', currency: 'CNY' }, { account: 'Income:Salary', amount: '-5000', currency: 'CNY' }] }),
  tx({ id: 't3', date: '2026-02-10', postings: [{ account: 'Assets:Alipay', amount: '-200', currency: 'CNY' }, { account: 'Expenses:Food', amount: '200', currency: 'CNY' }] }),
  tx({ id: 't4', date: '2026-03-05', postings: [{ account: 'Liabilities:CreditCard', amount: '-50', currency: 'CNY' }, { account: 'Expenses:Food', amount: '50', currency: 'CNY' }] }),
];

describe('netWorth', () => {
  it('calculateBalanceByType', () => {
    expect(calculateBalanceByType(sampleTx, 'Assets')).toBe('4700');   // -100+5000-200 = 4700
    expect(calculateBalanceByType(sampleTx, 'Liabilities')).toBe('-50');
  });

  it('calculateNetWorth', () => {
    const nw = calculateNetWorth(sampleTx);
    expect(nw.assets).toBe('4700');
    expect(nw.liabilities).toBe('50');
    expect(nw.netWorth).toBe('4650');
  });

  it('calculateNetWorthTrend', () => {
    const trend = calculateNetWorthTrend(sampleTx, ['2026-01-31', '2026-02-28']);
    expect(trend).toHaveLength(2);
    expect(trend[0].netWorth).toBe('4900');   // 截至1/31: -100+5000 = 4900 资产
    expect(parseFloat(trend[1].netWorth)).toBe(4700);
  });
});

describe('annualReport', () => {
  it('generateAnnualReport 2026', () => {
    const report = generateAnnualReport(sampleTx, 2026);
    expect(report.year).toBe(2026);
    expect(report.transactionCount).toBe(4);
    expect(report.totalExpense).toBe('350');    // 100+200+50
    expect(report.totalIncome).toBe('5000');
    expect(report.topCategories.length).toBeGreaterThan(0);
    expect(report.topCategories[0].category).toContain('Food');
    expect(report.monthlyTrend).toHaveLength(12);
    expect(report.dayOfWeekBreakdown).toHaveLength(7);
  });

  it('无数据年份返回空', () => {
    const report = generateAnnualReport(sampleTx, 2025);
    expect(report.transactionCount).toBe(0);
    expect(report.totalExpense).toBe('0');
  });
});

describe('accountTree', () => {
  it('buildAccountTree + calculateAccountTotalBalance', () => {
    const ledger = parseLedger([{ path: 'main.bean', content: '2026-01-01 open Assets:Alipay CNY\n2026-01-01 open Assets:Bank:CMB CNY\n2026-01-01 open Expenses:Food CNY\n' }]);
    const nodes = buildAccountTree(ledger.accounts, sampleTx);
    // 顶层应有 Assets、Expenses（Income/Liabilities 因无账户注册可能不出现）
    const topNames = nodes.map(n => n.name);
    expect(topNames).toContain('Assets');
    expect(topNames).toContain('Expenses');
    // Assets 总余额
    const assets = nodes.find(n => n.name === 'Assets');
    expect(calculateAccountTotalBalance(assets!)).toBe('4700');
  });

  it('calculateReport', () => {
    const ledger = parseLedger([{ path: 'main.bean', content: '' }]);
    const report = calculateReport({ ...ledger, files: [], transactions: sampleTx });
    expect(report.expense).toBe('350');
    expect(report.income).toBe('5000');
  });
});
