/**
 * LiteMall 数据库抽象层
 * 
 * 当前驱动：SQLite (better-sqlite3)
 * 未来驱动：MySQL (mysql2)
 * 
 * 对外暴露统一接口：get / run / all / transaction
 * 上层100+路由零改动即可切换数据库
 */

const config = require('../../config');
const EventEmitter = require('events');

class Database extends EventEmitter {
  constructor() {
    super();
    this.driver = config.dbDriver || 'sqlite';
    this.db = null;
    this.writeQueue = [];
    this.writing = false;
    this.stats = { reads: 0, writes: 0, queueHighWater: 0 };
  }

  // ==================== 连接管理 ====================

  async connect() {
    if (this.driver === 'mysql') {
      return this._connectMySQL();
    }
    return this._connectSQLite();
  }

  _connectSQLite() {
    const Database = require('better-sqlite3');
    this.db = new Database(config.dbPath);
    this.db.pragma('journal_mode = WAL');
    this.db.pragma('foreign_keys = ON');
    this.db.pragma('cache_size = -8000');  // 8MB cache
    this.db.pragma('synchronous = NORMAL'); // 平衡性能与安全
    console.log(`[DB] SQLite 已连接: ${config.dbPath} (WAL模式)`);
    return true;
  }

  async _connectMySQL() {
    try {
      const mysql = require('mysql2/promise');
      this.db = await mysql.createPool({
        host: config.mysql?.host || '127.0.0.1',
        port: config.mysql?.port || 3306,
        user: config.mysql?.user || 'litemall',
        password: config.mysql?.password || '',
        database: config.mysql?.database || 'litemall',
        waitForConnections: true,
        connectionLimit: config.mysql?.poolSize || 10,
        queueLimit: 0,
        enableKeepAlive: true,
        keepAliveInitialDelay: 0,
      });
      console.log(`[DB] MySQL 已连接: ${config.mysql?.host}:${config.mysql?.port}/${config.mysql?.database}`);
      return true;
    } catch (e) {
      console.error('[DB] MySQL连接失败:', e.message);
      throw e;
    }
  }

  // ==================== 读写队列（仅SQLite生效）====================

  /**
   * 将写操作加入队列，串行执行，缓解SQLite锁冲突
   */
  _enqueueWrite(fn) {
    return new Promise((resolve, reject) => {
      this.writeQueue.push({ fn, resolve, reject });
      this.stats.queueHighWater = Math.max(this.stats.queueHighWater, this.writeQueue.length);
      this._processQueue();
    });
  }

  _processQueue() {
    if (this.writing || this.writeQueue.length === 0) return;
    this.writing = true;
    const { fn, resolve, reject } = this.writeQueue.shift();
    try {
      const result = fn();
      resolve(result);
    } catch (err) {
      reject(err);
    } finally {
      this.writing = false;
      setImmediate(() => this._processQueue());
    }
  }

  // ==================== 核心查询方法 ====================

  /**
   * 查单条记录
   */
  async get(sql, params = []) {
    this.stats.reads++;
    if (this.driver === 'mysql') {
      const [rows] = await this.db.execute(sql, this._normalize(params));
      return rows[0] || null;
    }
    return this.db.prepare(sql).get(this._normalize(params)) || null;
  }

  /**
   * 查多条记录
   */
  async all(sql, params = []) {
    this.stats.reads++;
    if (this.driver === 'mysql') {
      const [rows] = await this.db.execute(sql, this._normalize(params));
      return rows;
    }
    return this.db.prepare(sql).all(this._normalize(params));
  }

  /**
   * 执行写操作（自动入队串行化）
   */
  async run(sql, params = []) {
    this.stats.writes++;
    if (this.driver === 'mysql') {
      const [result] = await this.db.execute(sql, this._normalize(params));
      return { lastInsertRowid: result.insertId, changes: result.affectedRows };
    }
    // SQLite写操作入队列，避免并发锁冲突
    return this._enqueueWrite(() => {
      const result = this.db.prepare(sql).run(this._normalize(params));
      return { lastInsertRowid: result.lastInsertRowid, changes: result.changes };
    });
  }

  /**
   * 事务
   */
  async transaction(fn) {
    if (this.driver === 'mysql') {
      const conn = await this.db.getConnection();
      try {
        await conn.beginTransaction();
        const result = await fn({
          get: async (sql, p) => { const [r] = await conn.execute(sql, this._normalize(p)); return r[0]; },
          run: async (sql, p) => { const [r] = await conn.execute(sql, this._normalize(p)); return r; },
        });
        await conn.commit();
        return result;
      } catch (e) {
        await conn.rollback();
        throw e;
      } finally {
        conn.release();
      }
    }
    // SQLite事务（同步执行，但包在队列里）
    return this._enqueueWrite(() => {
      return this.db.transaction(fn)();
    });
  }

  /**
   * 查询（返回原始结果集，兼容旧代码）
   */
  async query(sql, params = []) {
    return this.all(sql, params);
  }

  /**
   * 获取连接统计
   */
  getStats() {
    return {
      ...this.stats,
      queueLength: this.writeQueue.length,
      driver: this.driver,
    };
  }

  /**
   * 同步快速查询（兼容旧代码中同步调用的地方，后续逐步迁移）
   * 注意：仅SQLite支持同步查询，MySQL下会抛异常
   */
  getSync(sql, params = []) {
    if (this.driver === 'mysql') {
      throw new Error('MySQL模式下不支持同步查询，请使用 await db.get()');
    }
    return this.db.prepare(sql).get(this._normalize(params));
  }

  allSync(sql, params = []) {
    if (this.driver === 'mysql') {
      throw new Error('MySQL模式下不支持同步查询，请使用 await db.all()');
    }
    return this.db.prepare(sql).all(this._normalize(params));
  }

  // ==================== 工具方法 ====================

  _normalize(params) {
    if (params === null || params === undefined) return [];
    if (Array.isArray(params)) return params;
    if (typeof params === 'object') return Object.values(params);
    return [params];
  }

  /**
   * 关闭连接
   */
  async close() {
    if (this.driver === 'mysql') {
      await this.db.end();
    } else if (this.db) {
      this.db.close();
      this.db = null;
    }
  }
}

// ==================== 单例导出 ====================

const db = new Database();
db.connect().catch(e => {
  console.error('[DB] 初始化失败:', e.message);
  process.exit(1);
});

// 保持对旧接口的兼容（同步快速读取）
const compatGet = (sql, params) => db.getSync(sql, params);
const compatAll = (sql, params) => db.allSync(sql, params);

module.exports = db;
module.exports.get = (sql, params) => db.get(sql, params);
module.exports.run = (sql, params) => db.run(sql, params);
module.exports.all = (sql, params) => db.all(sql, params);
module.exports.transaction = (fn) => db.transaction(fn);
module.exports.query = (sql, params) => db.query(sql, params);
module.exports.getSync = (sql, params) => db.getSync(sql, params);
module.exports.allSync = (sql, params) => db.allSync(sql, params);
module.exports.close = () => db.close();
module.exports.getStats = () => db.getStats();
