import type { LedgerIndex } from '../core/types';

/**
 * 分类系统（双轨制）。
 *
 * 设计见 plan.md「决策 1」：
 * - 分类是应用本地表（name/keywords/icon/color），记账时通过 linkedAccount 映射到 Beancount 账户
 * - 与 Beancount 的关系：分类不写回 .bean，只在记账时把 linkedAccount 作为 posting account
 * - 匹配算法参考 BeeCount 的 CategoryMatcher，但关系模型用双轨制映射
 */

export interface Category {
  id: string;
  name: string;
  parentId?: string;          // 层级（UI 展示用，不映射到 .bean）
  type: 'income' | 'expense';
  linkedAccount: string;      // ★ 映射到 Beancount 账户，记账时作为 posting account
  icon?: string;              // UI 增强（仅本地）
  color?: string;             // UI 增强（仅本地）
  keywords: string[];         // 自动匹配关键词（仅本地匹配逻辑）
}

/** 分类匹配结果。 */
export interface CategoryMatch {
  category: Category | null;
  /** 匹配方式，便于调试/置信度判断。 */
  matchedBy: 'exact' | 'keyword' | 'fuzzy' | 'fallback' | 'none';
}

/**
 * 分类匹配：精确 → 关键词 → 模糊 → 兜底"其他"。
 * @param text 待匹配文本（通常是交易对手方/备注）
 * @param categories 候选分类列表
 */
export function matchCategory(text: string, categories: Category[]): CategoryMatch {
  const normalized = text.trim();
  if (!normalized) return { category: null, matchedBy: 'none' };

  // 1. 精确匹配（分类名等于文本）
  const exact = categories.find(c => c.name === normalized);
  if (exact) return { category: exact, matchedBy: 'exact' };

  // 2. 关键词匹配（任一关键词被文本包含；关键词最短 2 字符，避免单字误匹配）
  const byKeyword = categories.find(c =>
    c.keywords.some(k => k && k.length >= 2 && normalized.includes(k))
  );
  if (byKeyword) return { category: byKeyword, matchedBy: 'keyword' };

  // 3. 模糊匹配（包含关系，双向，最小长度 2 避免单字符误匹配）
  const fuzzy = categories.find(c =>
    (normalized.length >= 2 && normalized.includes(c.name)) ||
    (c.name.length >= 2 && c.name.includes(normalized))
  );
  if (fuzzy) return { category: fuzzy, matchedBy: 'fuzzy' };

  // 4. 兜底"其他"
  const fallback = categories.find(c => c.name === '其他' || c.name === 'Other') ?? null;
  return { category: fallback, matchedBy: fallback ? 'fallback' : 'none' };
}

/**
 * 解析分类到 Beancount 账户（双轨制核心）。
 *
 * 始终返回分类映射的真实账户名，不降级到 Uncategorized。
 * 如果账户在账本中不存在，valid=false，由导入流程自动 open。
 */
export function resolveCategoryAccount(
  category: Category | null,
  type: 'income' | 'expense',
  ledger: LedgerIndex,
): { account: string; valid: boolean; fallbackReason?: string } {
  if (!category) {
    // 未匹配分类时使用兜底账户
    const fallback = type === 'income' ? 'Income:未分类' : 'Expenses:未分类';
    return {
      account: fallback,
      valid: ledger.accounts.has(fallback),
      fallbackReason: '未匹配到分类',
    };
  }
  const exists = ledger.accounts.has(category.linkedAccount);
  return {
    account: category.linkedAccount,
    valid: exists,
    fallbackReason: exists ? undefined : `账户 ${category.linkedAccount} 尚未开户，将在导入时自动创建`,
  };
}

/** 根据类型筛选分类（支出/收入）。 */
export function filterByType(categories: Category[], type: 'income' | 'expense'): Category[] {
  return categories.filter(c => c.type === type);
}

/** 获取子分类（层级）。 */
export function getSubCategories(categories: Category[], parentId: string): Category[] {
  return categories.filter(c => c.parentId === parentId);
}

/** 获取顶层分类（无 parentId）。 */
export function getTopLevelCategories(categories: Category[]): Category[] {
  return categories.filter(c => !c.parentId);
}
