import initSqlJs, { Database as SqlJsDatabase, Statement } from 'sql.js';
import fs from 'fs';
import path from 'path';

const DB_PATH = process.env.DB_PATH || path.join(__dirname, '..', 'data', 'network.db');

let db: SqlJsDatabase | null = null;

export async function getDb(): Promise<SqlJsDatabase> {
  if (!db) {
    const SQL = await initSqlJs();

    // 确保 data 目录存在
    const dir = path.dirname(DB_PATH);
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }

    // 尝试从文件加载，否则创建新数据库
    if (fs.existsSync(DB_PATH)) {
      const buffer = fs.readFileSync(DB_PATH);
      db = new SQL.Database(buffer);
    } else {
      db = new SQL.Database();
    }

    db.run('PRAGMA journal_mode = WAL');
    db.run('PRAGMA foreign_keys = ON');
    initSchema(db);
    console.log('[DB] 数据库已初始化');
  }
  return db;
}

/**
 * 手动保存数据库到磁盘
 */
export function saveDb(): void {
  if (!db) return;
  const data = db.export();
  const buffer = Buffer.from(data);
  fs.writeFileSync(DB_PATH, buffer);
  console.log('[DB] 数据库已保存');
}

function initSchema(database: SqlJsDatabase): void {
  database.run(`
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      email TEXT UNIQUE NOT NULL,
      password_hash TEXT NOT NULL,
      role TEXT NOT NULL DEFAULT 'user' CHECK(role IN ('user', 'admin')),
      created_at TEXT NOT NULL DEFAULT (datetime('now'))
    )
  `);

  database.run(`
    CREATE TABLE IF NOT EXISTS devices (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL,
      device_name TEXT NOT NULL,
      device_fingerprint TEXT UNIQUE NOT NULL,
      public_key TEXT NOT NULL DEFAULT '',
      status TEXT NOT NULL DEFAULT 'offline' CHECK(status IN ('online', 'offline')),
      last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )
  `);

  database.run(`
    CREATE TABLE IF NOT EXISTS relay_nodes (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      host TEXT NOT NULL,
      port INTEGER NOT NULL,
      status TEXT NOT NULL DEFAULT 'offline' CHECK(status IN ('online', 'offline', 'busy')),
      load INTEGER NOT NULL DEFAULT 0,
      last_heartbeat_at TEXT NOT NULL DEFAULT (datetime('now'))
    )
  `);

  database.run(`
    CREATE TABLE IF NOT EXISTS connection_tokens (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER NOT NULL,
      device_id INTEGER NOT NULL,
      node_id INTEGER NOT NULL,
      token_hash TEXT NOT NULL,
      expires_at TEXT NOT NULL,
      used_at TEXT,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
      FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE,
      FOREIGN KEY (node_id) REFERENCES relay_nodes(id) ON DELETE CASCADE
    )
  `);

  database.run(`
    CREATE TABLE IF NOT EXISTS connection_logs (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      user_id INTEGER,
      device_id INTEGER,
      node_id INTEGER,
      action TEXT NOT NULL,
      status TEXT NOT NULL CHECK(status IN ('success', 'failed')),
      message TEXT NOT NULL DEFAULT '',
      created_at TEXT NOT NULL DEFAULT (datetime('now'))
    )
  `);

  // 索引
  database.run('CREATE INDEX IF NOT EXISTS idx_devices_user ON devices(user_id)');
  database.run('CREATE INDEX IF NOT EXISTS idx_devices_fingerprint ON devices(device_fingerprint)');
  database.run('CREATE INDEX IF NOT EXISTS idx_nodes_status ON relay_nodes(status)');
  database.run('CREATE INDEX IF NOT EXISTS idx_tokens_hash ON connection_tokens(token_hash)');
  database.run('CREATE INDEX IF NOT EXISTS idx_logs_created ON connection_logs(created_at)');
}

/**
 * 辅助函数：查询单行
 */
export function queryOne<T = Record<string, any>>(
  database: SqlJsDatabase,
  sql: string,
  params: any[] = []
): T | null {
  try {
    const stmt = database.prepare(sql);
    if (params.length > 0) stmt.bind(params);
    if (stmt.step()) {
      const row = stmt.getAsObject() as T;
      stmt.free();
      return row;
    }
    stmt.free();
    return null;
  } catch (err) {
    console.error('[DB] queryOne error:', sql, err);
    return null;
  }
}

/**
 * 辅助函数：查询多行
 */
export function queryAll<T = Record<string, any>>(
  database: SqlJsDatabase,
  sql: string,
  params: any[] = []
): T[] {
  try {
    const stmt = database.prepare(sql);
    if (params.length > 0) stmt.bind(params);
    const results: T[] = [];
    while (stmt.step()) {
      results.push(stmt.getAsObject() as T);
    }
    stmt.free();
    return results;
  } catch (err) {
    console.error('[DB] queryAll error:', sql, err);
    return [];
  }
}

/**
 * 辅助函数：执行 INSERT/UPDATE/DELETE
 */
export function execute(
  database: SqlJsDatabase,
  sql: string,
  params: any[] = []
): { changes: number; lastInsertRowid: number } {
  try {
    database.run(sql, params);
    const lastId = database.exec("SELECT last_insert_rowid() as id");
    const lastInsertRowid = lastId.length > 0 ? (lastId[0].values[0][0] as number) : 0;
    return {
      changes: database.getRowsModified(),
      lastInsertRowid,
    };
  } catch (err) {
    console.error('[DB] execute error:', sql, err);
    throw err;
  }
}

/**
 * 独立的数据库初始化脚本（用于 npm run db:init）
 */
if (require.main === module) {
  getDb().then(() => {
    saveDb();
    console.log('[DB] 数据库初始化完成:', DB_PATH);
    process.exit(0);
  });
}
