/**
 * 预算管理（plan.md「5.5 预算管理」）。
 * 纯本地虚拟概念（双轨制决策 1），不写回 .bean，仅用于统计/提醒。
 */

import { addDecimals, compareDecimals, divideDecimals, subtractDecimals, toDateString } from '../core/decimal';
import type { Transaction } from '../core/types';

export interface Budget {
  id: string;
  name: string;
  amount: string;
  period: 'monthly' | 'weekly' | 'yearly';
  /** 关联的分类账户（undefined = 总预算）。 */
  categoryAccount?: string;
  startDate: string;
}

export interface BudgetProgress {
  budget: Budget;
  spent: string;
  remaining: string;
  /** 使用百分比（0-100+）。 */
  percentage: number;
  /** 是否超支。 */
  overBudget: boolean;
}

/** 计算单个预算在指定交易集合上的进度。 */
export function calculateBudgetProgress(
  budget: Budget,
  transactions: Transaction[],
  currentDate: string,
): BudgetProgress {
  const periodTx = filterByPeriod(transactions, budget.period, currentDate, budget.categoryAccount);
  const spentAmounts: string[] = [];
  for (const t of periodTx) {
    for (const p of t.postings) {
      if (!p.amount) continue;
      const target = budget.categoryAccount;
      if (target) {
        if (p.account === target || p.account.startsWith(target + ':')) {
          spentAmounts.push(p.amount);
        }
      } else {
        if (p.account.startsWith('Expenses:')) {
          spentAmounts.push(p.amount);
        }
      }
    }
  }
  const spent = addDecimals(spentAmounts.length ? spentAmounts : ['0']);
  const remaining = subtractDecimals(budget.amount, spent);
  // 使用 divideDecimals 计算百分比，避免 parseFloat 精度问题
  let percentage = 0;
  if (compareDecimals(budget.amount, '0') > 0) {
    try {
      const ratio = divideDecimals(spent, budget.amount, 8);
      percentage = parseFloat(ratio) * 100;
    } catch {
      percentage = 0;
    }
  }

  return {
    budget,
    spent,
    remaining,
    percentage: Math.round(percentage * 100) / 100,
    overBudget: remaining.startsWith('-'),
  };
}

/** 按周期 + 分类过滤交易。 */
function filterByPeriod(
  transactions: Transaction[],
  period: Budget['period'],
  currentDate: string,
  categoryAccount?: string,
): Transaction[] {
  const range = getPeriodRange(period, currentDate);
  return transactions.filter(t => {
    const date = t.date.slice(0, 10);
    if (date < range.start || date > range.end) return false;
    if (categoryAccount) {
      return t.postings.some(p => p.account === categoryAccount || p.account.startsWith(categoryAccount));
    }
    return true;
  });
}

/** 计算周期的起止日期。 */
export function getPeriodRange(period: Budget['period'], currentDate: string): { start: string; end: string } {
  // new Date('YYYY-MM-DD') 按 UTC 解析，负时区会把边界日（如 07-01）算到前一天；
  // 改为 split 构造本地 Date，与 periodNav 的 parse 一致
  const [y, m, dNum] = currentDate.slice(0, 10).split('-').map(Number);
  const d = new Date(y, m - 1, dNum);
  const year = d.getFullYear();
  const month = d.getMonth();
  switch (period) {
    case 'weekly': {
      const day = d.getDay() || 7;  // 周日=7
      const start = new Date(d);
      start.setDate(d.getDate() - day + 1);
      const end = new Date(start);
      end.setDate(start.getDate() + 6);
      return { start: toDateString(start), end: toDateString(end) };
    }
    case 'yearly':
      return { start: `${year}-01-01`, end: `${year}-12-31` };
    case 'monthly':
    default: {
      // 下月第 0 天 = 本月最后一天
      const lastDay = new Date(year, month + 1, 0);
      return {
        start: `${year}-${String(month + 1).padStart(2, '0')}-01`,
        end: toDateString(lastDay),
      };
    }
  }
}
