// ZCLAW 数据库管理
import Database from 'better-sqlite3';
import { existsSync, mkdirSync } from 'fs';
import { dirname } from 'path';
import { SCHEMA_SQL } from './schema';
import { createLogger } from '../utils/logger';

const log = createLogger('Database');

let _db: Database.Database | null = null;

export function initDatabase(dbPath: string): Database.Database {
  // 确保目录存在
  const dir = dirname(dbPath);
  if (!existsSync(dir)) {
    mkdirSync(dir, { recursive: true });
  }

  _db = new Database(dbPath);

  // 启用 WAL 模式提升性能
  _db.pragma('journal_mode = WAL');
  _db.pragma('foreign_keys = ON');

  // 创建表
  _db.exec(SCHEMA_SQL);

  log.info(`Database initialized at ${dbPath}`);
  return _db;
}

export function getDatabase(): Database.Database {
  if (!_db) {
    throw new Error('Database not initialized. Call initDatabase() first.');
  }
  return _db;
}

export function closeDatabase(): void {
  if (_db) {
    _db.close();
    _db = null;
    log.info('Database closed');
  }
}

// 通用 CRUD 辅助
export class BaseDAO<T extends Record<string, any>> {
  constructor(
    protected tableName: string,
    protected db: Database.Database = getDatabase()
  ) {}

  findById(id: string): T | undefined {
    return this.db.prepare(`SELECT * FROM ${this.tableName} WHERE id = ?`).get(id) as T | undefined;
  }

  findAll(where?: string, params?: any[]): T[] {
    const sql = where
      ? `SELECT * FROM ${this.tableName} WHERE ${where}`
      : `SELECT * FROM ${this.tableName}`;
    return (params ? this.db.prepare(sql).all(...params) : this.db.prepare(sql).all()) as T[];
  }

  insert(data: Partial<T>): void {
    const keys = Object.keys(data);
    const placeholders = keys.map(() => '?').join(', ');
    const sql = `INSERT OR REPLACE INTO ${this.tableName} (${keys.join(', ')}) VALUES (${placeholders})`;
    this.db.prepare(sql).run(...Object.values(data));
  }

  update(id: string, data: Partial<T>): void {
    const sets = Object.keys(data).map(k => `${k} = ?`).join(', ');
    const sql = `UPDATE ${this.tableName} SET ${sets} WHERE id = ?`;
    this.db.prepare(sql).run(...Object.values(data), id);
  }

  delete(id: string): void {
    this.db.prepare(`DELETE FROM ${this.tableName} WHERE id = ?`).run(id);
  }

  count(where?: string, params?: any[]): number {
    const sql = where
      ? `SELECT COUNT(*) as count FROM ${this.tableName} WHERE ${where}`
      : `SELECT COUNT(*) as count FROM ${this.tableName}`;
    const result = params
      ? this.db.prepare(sql).get(...params) as { count: number }
      : this.db.prepare(sql).get() as { count: number };
    return result.count;
  }
}
