/**
 * 数据库 Schema 版本与迁移（plan.md「0.2 数据库 Schema 版本与迁移」）。
 *
 * 缓存层表结构简单，按 Phase 需要逐步添加。
 * 迁移采用版本号 + 迁移函数，幂等助手（IF NOT EXISTS）抗部分状态重跑。
 */

import { logger } from '../utils/logger';

export const SCHEMA_VERSION = 2;

/** v1：基础缓存表。 */
const V1 = [
  `CREATE TABLE IF NOT EXISTS ledger_files (path TEXT PRIMARY KEY, content TEXT NOT NULL, checksum TEXT NOT NULL)`,
  `CREATE TABLE IF NOT EXISTS imported_events (id TEXT PRIMARY KEY, payload TEXT NOT NULL, committed_transaction TEXT)`,
  `CREATE TABLE IF NOT EXISTS rules (id TEXT PRIMARY KEY, priority INTEGER NOT NULL, payload TEXT NOT NULL)`,
  `CREATE TABLE IF NOT EXISTS drafts (id TEXT PRIMARY KEY, payload TEXT NOT NULL, created_at TEXT NOT NULL)`,
];

/** v2：双轨制映射表（categories/tags/credit_cards，plan.md 决策 1）。 */
const V2 = [
  `CREATE TABLE IF NOT EXISTS categories (id TEXT PRIMARY KEY, name TEXT NOT NULL, parent_id TEXT, type TEXT NOT NULL, linked_account TEXT NOT NULL, icon TEXT, color TEXT, keywords TEXT, priority INTEGER DEFAULT 0)`,
  `CREATE TABLE IF NOT EXISTS tags (id TEXT PRIMARY KEY, name TEXT NOT NULL, color TEXT NOT NULL)`,
  `CREATE TABLE IF NOT EXISTS credit_cards (id TEXT PRIMARY KEY, name TEXT NOT NULL, last_four TEXT, bank_name TEXT, billing_day INTEGER, payment_day INTEGER, credit_limit TEXT, currency TEXT, linked_account TEXT NOT NULL)`,
];

const MIGRATIONS: Record<number, string[]> = {
  1: V1,
  2: V2,
  // 后续版本按 Phase 需要追加：
  // 3: [`CREATE TABLE IF NOT EXISTS budgets (...)`, ...],
  // 4: [`CREATE TABLE IF NOT EXISTS recurring (...)`, ...],
  // 5: [`CREATE TABLE IF NOT EXISTS attachments (...)`, ...],
  // 6: [`CREATE TABLE IF NOT EXISTS exchange_rates (...)`, ...],
  // 7: [`CREATE TABLE IF NOT EXISTS sync_errors (...)`, ...],
  // 8: [`CREATE TABLE IF NOT EXISTS logs (...)`, ...],
};

/** SQLite 数据库抽象（生产用 expo-sqlite，测试用 mock）。 */
export interface MigrationDb {
  execAsync(sql: string): Promise<unknown>;
  getAsync<T>(sql: string, ...params: unknown[]): Promise<T | null>;
  runAsync(sql: string, ...params: unknown[]): Promise<unknown>;
}

async function getSchemaVersion(db: MigrationDb): Promise<number> {
  const row = await db.getAsync<{ user_version: number }>('PRAGMA user_version');
  return row?.user_version ?? 0;
}

async function setSchemaVersion(db: MigrationDb, version: number): Promise<void> {
  await db.execAsync(`PRAGMA user_version = ${version}`);
}

/** 执行迁移（从当前版本升级到 SCHEMA_VERSION）。已是最新版本则跳过。 */
export async function migrateDb(db: MigrationDb): Promise<void> {
  const current = await getSchemaVersion(db);
  if (current >= SCHEMA_VERSION) return;  // 已是最新，完全跳过（幂等）

  logger.info('storage', `准备升级数据库 Schema: v${current} -> v${SCHEMA_VERSION}`);
  await db.execAsync('BEGIN TRANSACTION');
  try {
    for (let v = current + 1; v <= SCHEMA_VERSION; v++) {
      const statements = MIGRATIONS[v];
      if (!statements) continue;
      for (const sql of statements) {
        logger.debug('storage', `执行迁移 SQL (v${v}): ${sql}`);
        await db.execAsync(sql);
      }
    }
    await setSchemaVersion(db, SCHEMA_VERSION);
    await db.execAsync('COMMIT');
    logger.info('storage', `数据库 Schema 成功升级到 v${SCHEMA_VERSION}`);
  } catch (e) {
    await db.execAsync('ROLLBACK');
    logger.error('storage', `数据库 Schema 升级失败 (v${current} -> v${SCHEMA_VERSION})，已执行 ROLLBACK`, e);
    throw e;
  }
}

/** 内存迁移 DB（测试用，记录执行过的语句）。 */
export class MemoryMigrationDb implements MigrationDb {
  public executed: string[] = [];
  private data = new Map<string, unknown>();

  async execAsync(sql: string): Promise<unknown> {
    this.executed.push(sql);
    if (sql.startsWith('PRAGMA user_version')) {
      const m = sql.match(/user_version\s*=\s*(\d+)/);
      if (m) this.data.set('user_version', parseInt(m[1], 10));
    }
    return undefined;
  }
  async getAsync<T>(sql: string): Promise<T | null> {
    if (sql === 'PRAGMA user_version') {
      return { user_version: this.data.get('user_version') ?? 0 } as T;
    }
    return null;
  }
  async runAsync(): Promise<unknown> { return undefined; }
}
