/**
 * 规则导入/导出（plan.md「5.12 规则导入/导出」）。
 *
 * 参考 AutoAccounting 的云规则分发系统：
 * - 导出：把规则列表序列化为 JSON 文件
 * - 导入：读取 JSON 文件，校验格式，合并到现有规则
 *
 * 文件读写通过注入抽象（生产用 expo-file-system，测试用 mock）。
 */

import type { Rule } from '../domain/core/types';
import type { Category } from '../domain/taxonomy/categories';
import { hash } from '../domain/core/ledger';

/** 规则包格式（可分享/导入）。 */
export interface RuleBundle {
  version: 1;
  exportedAt: string;
  rules: Rule[];
  categories?: Category[];
}

/** 文件系统抽象（规则导入导出用）。 */
export interface RuleFileSync {
  write(path: string, content: string): Promise<void>;
  read(path: string): Promise<string>;
  pickFile(): Promise<string | null>;
}

/** 导出规则为 JSON 文件。 */
export async function exportRules(
  rules: Rule[],
  categories: Category[] | undefined,
  fs: RuleFileSync,
  path: string,
): Promise<string> {
  const bundle: RuleBundle = {
    version: 1,
    exportedAt: new Date().toISOString(),
    rules,
    ...(categories ? { categories } : {}),
  };
  const json = JSON.stringify(bundle, null, 2);
  await fs.write(path, json);
  return path;
}

/** 从 JSON 文件导入规则。 */
export async function importRules(
  fs: RuleFileSync,
  path: string,
): Promise<RuleBundle> {
  const json = await fs.read(path);
  return parseRuleBundle(json);
}

/** 解析规则包 JSON（校验格式）。 */
export function parseRuleBundle(json: string): RuleBundle {
  const data = JSON.parse(json) as RuleBundle;
  if (data.version !== 1) throw new Error(`不支持的规则包版本: ${data.version}`);
  if (!Array.isArray(data.rules)) throw new Error('规则包格式错误：rules 非数组');
  // 校验每条规则的最小完整性
  for (const rule of data.rules) {
    if (!rule.id || typeof rule.priority !== 'number') {
      throw new Error(`规则格式错误: ${JSON.stringify(rule).slice(0, 100)}`);
    }
  }
  return data;
}

/** 校验规则是否有效。 */
export function validateRule(rule: unknown): rule is Rule {
  if (typeof rule !== 'object' || rule === null) return false;
  const r = rule as Record<string, unknown>;
  return typeof r.id === 'string' && typeof r.priority === 'number' && typeof r.sourceAccount === 'string' && typeof r.categoryAccount === 'string';
}

/** 合并导入的规则到现有规则（按 id 去重，导入的覆盖同名）。 */
export function mergeRules(
  existing: Rule[],
  imported: Rule[],
): Rule[] {
  const byId = new Map(existing.map(r => [r.id, r]));
  for (const rule of imported) {
    byId.set(rule.id, rule);
  }
  return [...byId.values()].sort((a, b) => b.priority - a.priority);
}

/** 计算规则包校验和（用于版本对比）。 */
export function ruleBundleChecksum(bundle: RuleBundle): string {
  return hash(JSON.stringify(bundle));
}

/** 模拟文件系统（测试用）。 */
export class MockRuleFileSync implements RuleFileSync {
  public files = new Map<string, string>();
  public pickedPath: string | null = null;

  async write(path: string, content: string): Promise<void> {
    this.files.set(path, content);
  }
  async read(path: string): Promise<string> {
    const content = this.files.get(path);
    if (!content) throw new Error(`文件不存在: ${path}`);
    return content;
  }
  async pickFile(): Promise<string | null> {
    return this.pickedPath;
  }
}
