import * as crypto from 'crypto';
import * as path from 'path';
import * as fs from 'fs';
import { app } from 'electron';
import initSqlJs from 'sql.js';
import type { Database as SqlJsDatabase, SqlJsStatic } from 'sql.js';
import { v4 as uuidv4 } from 'uuid';

// =============================================================================
// sql.js WASM 文件路径
// =============================================================================
function getSqlJsWasmPath(): string {
  // 在开发环境中，WASM 文件在 node_modules 中
  // 在生产环境中，WASM 文件被复制到 extraResources 目录
  const isDev = !app.isPackaged;

  if (isDev) {
    // 开发环境: 使用 node_modules 中的文件
    return path.join(__dirname, '../../node_modules/sql.js/dist/sql-wasm.wasm');
  } else {
    // 生产环境: 使用 extraResources 中的文件
    return path.join(process.resourcesPath, 'sql-wasm.wasm');
  }
}

// =============================================================================
// 数据库路径
// =============================================================================
function getDatabasePath(): string {
  const userDataPath = app.getPath('userData');
  return path.join(userDataPath, 'service-party.db');
}

// =============================================================================
// 加密配置
// =============================================================================
const ALGORITHM = 'aes-256-gcm';
const KEY_LENGTH = 32;
const IV_LENGTH = 16;
const SALT_LENGTH = 32;
const TAG_LENGTH = 16;
const ITERATIONS = 100000;

// =============================================================================
// 数据类型定义
// =============================================================================

export interface ShareRecord {
  id: string;
  session_id: string;
  wallet_name: string;
  party_id: string;
  party_index: number;
  threshold_t: number;
  threshold_n: number;
  public_key_hex: string;
  encrypted_share: string;
  created_at: string;
  last_used_at: string | null;
  participants_json: string;  // JSON 存储参与者列表
}

export interface DerivedAddressRecord {
  id: string;
  share_id: string;
  chain: string;
  derivation_path: string;
  address: string;
  public_key_hex: string;
  created_at: string;
}

export interface SigningHistoryRecord {
  id: string;
  share_id: string;
  session_id: string;
  message_hash: string;
  signature: string | null;
  status: 'pending' | 'in_progress' | 'completed' | 'failed';
  error_message: string | null;
  created_at: string;
  completed_at: string | null;
}

export interface SettingsRecord {
  key: string;
  value: string;
}

// =============================================================================
// 数据库管理类 (使用 sql.js - 纯 JavaScript SQLite)
// =============================================================================

export class DatabaseManager {
  private db: SqlJsDatabase | null = null;
  private SQL: SqlJsStatic | null = null;
  private dbPath: string;
  private initPromise: Promise<void>;

  constructor() {
    this.dbPath = getDatabasePath();
    this.initPromise = this.initialize();
  }

  /**
   * 初始化数据库
   */
  private async initialize(): Promise<void> {
    // 获取 WASM 文件路径
    const wasmPath = getSqlJsWasmPath();
    console.log('[Database] App packaged:', app.isPackaged);
    console.log('[Database] Resources path:', process.resourcesPath);
    console.log('[Database] WASM path:', wasmPath);
    console.log('[Database] WASM exists:', fs.existsSync(wasmPath));

    // 初始化 sql.js (加载 WASM)
    // 使用 wasmBinary 直接加载 WASM 文件，这在打包环境中更可靠
    let config: { wasmBinary?: ArrayBuffer; locateFile?: (file: string) => string } = {};

    if (fs.existsSync(wasmPath)) {
      // 直接读取 WASM 文件作为 ArrayBuffer - 这种方式更可靠
      const wasmBuffer = fs.readFileSync(wasmPath);
      config.wasmBinary = wasmBuffer.buffer.slice(
        wasmBuffer.byteOffset,
        wasmBuffer.byteOffset + wasmBuffer.byteLength
      );
      console.log('[Database] WASM loaded as binary, size:', wasmBuffer.length);
    } else {
      console.warn('[Database] WASM file not found, sql.js will try to load from default location');
      // 作为备用方案，使用 locateFile
      config.locateFile = (file: string) => {
        console.log('[Database] locateFile called for:', file);
        return file;
      };
    }

    this.SQL = await initSqlJs(config);

    // 如果数据库文件存在，加载它
    if (fs.existsSync(this.dbPath)) {
      const buffer = fs.readFileSync(this.dbPath);
      this.db = new this.SQL.Database(buffer);
    } else {
      this.db = new this.SQL.Database();
    }

    // 创建表结构
    this.createTables();
    this.saveToFile();
  }

  /**
   * 确保数据库已初始化
   */
  private async ensureReady(): Promise<void> {
    await this.initPromise;
  }

  /**
   * 等待数据库初始化完成（公开方法）
   */
  async waitForReady(): Promise<void> {
    await this.initPromise;
  }

  /**
   * 创建表结构
   */
  private createTables(): void {
    if (!this.db) return;

    this.db.run(`
      CREATE TABLE IF NOT EXISTS shares (
        id TEXT PRIMARY KEY,
        session_id TEXT NOT NULL,
        wallet_name TEXT NOT NULL,
        party_id TEXT NOT NULL,
        party_index INTEGER NOT NULL,
        threshold_t INTEGER NOT NULL,
        threshold_n INTEGER NOT NULL,
        public_key_hex TEXT NOT NULL,
        encrypted_share TEXT NOT NULL,
        created_at TEXT NOT NULL,
        last_used_at TEXT,
        participants_json TEXT NOT NULL DEFAULT '[]'
      )
    `);

    this.db.run(`
      CREATE TABLE IF NOT EXISTS derived_addresses (
        id TEXT PRIMARY KEY,
        share_id TEXT NOT NULL,
        chain TEXT NOT NULL,
        derivation_path TEXT NOT NULL,
        address TEXT NOT NULL,
        public_key_hex TEXT NOT NULL,
        created_at TEXT NOT NULL,
        UNIQUE(share_id, chain, derivation_path)
      )
    `);

    this.db.run(`
      CREATE TABLE IF NOT EXISTS signing_history (
        id TEXT PRIMARY KEY,
        share_id TEXT NOT NULL,
        session_id TEXT NOT NULL,
        message_hash TEXT NOT NULL,
        signature TEXT,
        status TEXT NOT NULL DEFAULT 'pending',
        error_message TEXT,
        created_at TEXT NOT NULL,
        completed_at TEXT
      )
    `);

    this.db.run(`
      CREATE TABLE IF NOT EXISTS settings (
        key TEXT PRIMARY KEY,
        value TEXT NOT NULL
      )
    `);

    // 已处理消息表 - 用于消息去重，防止重连后重复处理消息
    this.db.run(`
      CREATE TABLE IF NOT EXISTS processed_messages (
        message_id TEXT PRIMARY KEY,
        session_id TEXT NOT NULL,
        processed_at TEXT NOT NULL
      )
    `);

    // 创建索引
    this.db.run(`CREATE INDEX IF NOT EXISTS idx_shares_session ON shares(session_id)`);
    this.db.run(`CREATE INDEX IF NOT EXISTS idx_addresses_share ON derived_addresses(share_id)`);
    this.db.run(`CREATE INDEX IF NOT EXISTS idx_addresses_chain ON derived_addresses(chain)`);
    this.db.run(`CREATE INDEX IF NOT EXISTS idx_history_share ON signing_history(share_id)`);
    this.db.run(`CREATE INDEX IF NOT EXISTS idx_history_status ON signing_history(status)`);
    this.db.run(`CREATE INDEX IF NOT EXISTS idx_processed_messages_session ON processed_messages(session_id)`);

    // 插入默认设置
    this.db.run(`INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)`, ['message_router_url', 'mpc-grpc.szaiai.com:443']);
    this.db.run(`INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)`, ['auto_backup', 'false']);
    this.db.run(`INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)`, ['backup_path', '']);
  }

  /**
   * 保存数据库到文件
   */
  private saveToFile(): void {
    if (!this.db) return;
    const data = this.db.export();
    const buffer = Buffer.from(data);
    fs.writeFileSync(this.dbPath, buffer);
  }

  /**
   * 从密码派生密钥
   */
  private deriveKey(password: string, salt: Buffer): Buffer {
    return crypto.pbkdf2Sync(password, salt, ITERATIONS, KEY_LENGTH, 'sha256');
  }

  /**
   * 加密数据
   */
  private encrypt(data: string, password: string): string {
    const salt = crypto.randomBytes(SALT_LENGTH);
    const key = this.deriveKey(password, salt);
    const iv = crypto.randomBytes(IV_LENGTH);

    const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
    let encrypted = cipher.update(data, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    const tag = cipher.getAuthTag();

    // 格式: salt(hex) + iv(hex) + tag(hex) + encrypted(hex)
    return salt.toString('hex') + iv.toString('hex') + tag.toString('hex') + encrypted;
  }

  /**
   * 解密数据
   */
  private decrypt(encryptedData: string, password: string): string {
    const salt = Buffer.from(encryptedData.slice(0, SALT_LENGTH * 2), 'hex');
    const iv = Buffer.from(encryptedData.slice(SALT_LENGTH * 2, SALT_LENGTH * 2 + IV_LENGTH * 2), 'hex');
    const tag = Buffer.from(encryptedData.slice(SALT_LENGTH * 2 + IV_LENGTH * 2, SALT_LENGTH * 2 + IV_LENGTH * 2 + TAG_LENGTH * 2), 'hex');
    const encrypted = encryptedData.slice(SALT_LENGTH * 2 + IV_LENGTH * 2 + TAG_LENGTH * 2);

    const key = this.deriveKey(password, salt);
    const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
    decipher.setAuthTag(tag);

    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');

    return decrypted;
  }

  /**
   * 将查询结果转换为对象数组
   */
  private queryToObjects<T>(sql: string, params: unknown[] = []): T[] {
    if (!this.db) return [];

    const results = this.db.exec(sql, params);
    if (results.length === 0) return [];

    const columns = results[0].columns;
    return results[0].values.map((row: (number | string | Uint8Array | null)[]) => {
      const obj: Record<string, unknown> = {};
      columns.forEach((col: string, i: number) => {
        obj[col] = row[i];
      });
      return obj as T;
    });
  }

  /**
   * 查询单个对象
   */
  private queryOne<T>(sql: string, params: unknown[] = []): T | undefined {
    const results = this.queryToObjects<T>(sql, params);
    return results[0];
  }

  // ===========================================================================
  // Share 操作
  // ===========================================================================

  /**
   * 保存 share
   */
  saveShare(params: {
    sessionId: string;
    walletName: string;
    partyId: string;
    partyIndex: number;
    thresholdT: number;
    thresholdN: number;
    publicKeyHex: string;
    rawShare: string;
    participants: Array<{ partyId: string; name: string }>;
  }, password: string): ShareRecord {
    if (!this.db) throw new Error('Database not initialized');

    const id = uuidv4();
    const encryptedShare = this.encrypt(params.rawShare, password);
    const now = new Date().toISOString();

    this.db.run(`
      INSERT INTO shares (
        id, session_id, wallet_name, party_id, party_index,
        threshold_t, threshold_n, public_key_hex, encrypted_share,
        created_at, participants_json
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `, [
      id,
      params.sessionId,
      params.walletName,
      params.partyId,
      params.partyIndex,
      params.thresholdT,
      params.thresholdN,
      params.publicKeyHex,
      encryptedShare,
      now,
      JSON.stringify(params.participants)
    ]);

    this.saveToFile();

    return {
      id,
      session_id: params.sessionId,
      wallet_name: params.walletName,
      party_id: params.partyId,
      party_index: params.partyIndex,
      threshold_t: params.thresholdT,
      threshold_n: params.thresholdN,
      public_key_hex: params.publicKeyHex,
      encrypted_share: encryptedShare,
      created_at: now,
      last_used_at: null,
      participants_json: JSON.stringify(params.participants),
    };
  }

  /**
   * 获取所有 share (不含加密数据)
   */
  listShares(): Omit<ShareRecord, 'encrypted_share'>[] {
    return this.queryToObjects<Omit<ShareRecord, 'encrypted_share'>>(`
      SELECT id, session_id, wallet_name, party_id, party_index,
             threshold_t, threshold_n, public_key_hex, created_at,
             last_used_at, participants_json
      FROM shares
      ORDER BY created_at DESC
    `);
  }

  /**
   * 获取单个 share (解密)
   */
  getShare(id: string, password: string): ShareRecord & { raw_share: string } {
    const share = this.queryOne<ShareRecord>(`SELECT * FROM shares WHERE id = ?`, [id]);

    if (!share) {
      throw new Error('Share not found');
    }

    const rawShare = this.decrypt(share.encrypted_share, password);

    return {
      ...share,
      raw_share: rawShare,
    };
  }

  /**
   * 更新 share 最后使用时间
   */
  updateShareLastUsed(id: string): void {
    if (!this.db) return;
    this.db.run(`UPDATE shares SET last_used_at = ? WHERE id = ?`, [new Date().toISOString(), id]);
    this.saveToFile();
  }

  /**
   * 删除 share (级联删除派生地址和签名历史)
   */
  deleteShare(id: string): void {
    if (!this.db) return;
    // 手动级联删除
    this.db.run(`DELETE FROM derived_addresses WHERE share_id = ?`, [id]);
    this.db.run(`DELETE FROM signing_history WHERE share_id = ?`, [id]);
    this.db.run(`DELETE FROM shares WHERE id = ?`, [id]);
    this.saveToFile();
  }

  // ===========================================================================
  // 派生地址操作
  // ===========================================================================

  /**
   * 保存派生地址
   */
  saveDerivedAddress(params: {
    shareId: string;
    chain: string;
    derivationPath: string;
    address: string;
    publicKeyHex: string;
  }): DerivedAddressRecord {
    if (!this.db) throw new Error('Database not initialized');

    const id = uuidv4();
    const now = new Date().toISOString();

    this.db.run(`
      INSERT OR REPLACE INTO derived_addresses (
        id, share_id, chain, derivation_path, address, public_key_hex, created_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?)
    `, [
      id,
      params.shareId,
      params.chain,
      params.derivationPath,
      params.address,
      params.publicKeyHex,
      now
    ]);

    this.saveToFile();

    return {
      id,
      share_id: params.shareId,
      chain: params.chain,
      derivation_path: params.derivationPath,
      address: params.address,
      public_key_hex: params.publicKeyHex,
      created_at: now,
    };
  }

  /**
   * 获取 share 的所有派生地址
   */
  getAddressesByShare(shareId: string): DerivedAddressRecord[] {
    return this.queryToObjects<DerivedAddressRecord>(`
      SELECT * FROM derived_addresses
      WHERE share_id = ?
      ORDER BY chain, derivation_path
    `, [shareId]);
  }

  /**
   * 根据链获取地址
   */
  getAddressByChain(shareId: string, chain: string): DerivedAddressRecord | undefined {
    return this.queryOne<DerivedAddressRecord>(`
      SELECT * FROM derived_addresses
      WHERE share_id = ? AND chain = ?
      LIMIT 1
    `, [shareId, chain]);
  }

  /**
   * 获取所有指定链的地址
   */
  getAllAddressesByChain(chain: string): DerivedAddressRecord[] {
    return this.queryToObjects<DerivedAddressRecord>(`
      SELECT * FROM derived_addresses
      WHERE chain = ?
      ORDER BY created_at DESC
    `, [chain]);
  }

  // ===========================================================================
  // 签名历史操作
  // ===========================================================================

  /**
   * 创建签名历史记录
   */
  createSigningHistory(params: {
    shareId: string;
    sessionId: string;
    messageHash: string;
  }): SigningHistoryRecord {
    if (!this.db) throw new Error('Database not initialized');

    const id = uuidv4();
    const now = new Date().toISOString();

    this.db.run(`
      INSERT INTO signing_history (
        id, share_id, session_id, message_hash, status, created_at
      ) VALUES (?, ?, ?, ?, 'pending', ?)
    `, [id, params.shareId, params.sessionId, params.messageHash, now]);

    this.saveToFile();

    return {
      id,
      share_id: params.shareId,
      session_id: params.sessionId,
      message_hash: params.messageHash,
      signature: null,
      status: 'pending',
      error_message: null,
      created_at: now,
      completed_at: null,
    };
  }

  /**
   * 更新签名历史状态
   */
  updateSigningHistory(id: string, params: {
    status: SigningHistoryRecord['status'];
    signature?: string;
    errorMessage?: string;
  }): void {
    if (!this.db) return;

    const completedAt = params.status === 'completed' || params.status === 'failed'
      ? new Date().toISOString()
      : null;

    this.db.run(`
      UPDATE signing_history
      SET status = ?, signature = ?, error_message = ?, completed_at = ?
      WHERE id = ?
    `, [
      params.status,
      params.signature || null,
      params.errorMessage || null,
      completedAt,
      id
    ]);

    this.saveToFile();
  }

  /**
   * 获取 share 的签名历史
   */
  getSigningHistoryByShare(shareId: string): SigningHistoryRecord[] {
    return this.queryToObjects<SigningHistoryRecord>(`
      SELECT * FROM signing_history
      WHERE share_id = ?
      ORDER BY created_at DESC
    `, [shareId]);
  }

  // ===========================================================================
  // 设置操作
  // ===========================================================================

  /**
   * 获取设置
   */
  getSetting(key: string): string | undefined {
    const row = this.queryOne<{ value: string }>(`SELECT value FROM settings WHERE key = ?`, [key]);
    return row?.value;
  }

  /**
   * 保存设置
   */
  setSetting(key: string, value: string): void {
    if (!this.db) return;
    this.db.run(`INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)`, [key, value]);
    this.saveToFile();
  }

  /**
   * 获取所有设置
   */
  getAllSettings(): Record<string, string> {
    const rows = this.queryToObjects<SettingsRecord>(`SELECT key, value FROM settings`);
    const settings: Record<string, string> = {};
    for (const row of rows) {
      settings[row.key] = row.value;
    }
    return settings;
  }

  // ===========================================================================
  // 消息去重操作
  // ===========================================================================

  /**
   * 检查消息是否已处理
   */
  isMessageProcessed(messageId: string): boolean {
    const row = this.queryOne<{ message_id: string }>(
      `SELECT message_id FROM processed_messages WHERE message_id = ?`,
      [messageId]
    );
    return !!row;
  }

  /**
   * 标记消息为已处理
   */
  markMessageProcessed(messageId: string, sessionId: string): void {
    if (!this.db) return;
    const now = new Date().toISOString();
    this.db.run(
      `INSERT OR IGNORE INTO processed_messages (message_id, session_id, processed_at) VALUES (?, ?, ?)`,
      [messageId, sessionId, now]
    );
    this.saveToFile();
  }

  /**
   * 清理指定会话的已处理消息记录
   * 当会话完成后调用，释放空间
   */
  clearProcessedMessages(sessionId: string): void {
    if (!this.db) return;
    this.db.run(`DELETE FROM processed_messages WHERE session_id = ?`, [sessionId]);
    this.saveToFile();
  }

  /**
   * 清理过期的已处理消息记录（超过24小时）
   * 可在应用启动时调用
   */
  cleanupOldProcessedMessages(): void {
    if (!this.db) return;
    const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
    this.db.run(`DELETE FROM processed_messages WHERE processed_at < ?`, [cutoff]);
    this.saveToFile();
  }

  // ===========================================================================
  // 导入导出
  // ===========================================================================

  /**
   * 导出 share (加密备份)
   */
  exportShare(id: string, password: string): Buffer {
    const share = this.getShare(id, password);
    const addresses = this.getAddressesByShare(id);

    const exportData = {
      version: '1.0.0',
      exportedAt: new Date().toISOString(),
      share: {
        session_id: share.session_id,
        wallet_name: share.wallet_name,
        party_id: share.party_id,
        party_index: share.party_index,
        threshold_t: share.threshold_t,
        threshold_n: share.threshold_n,
        public_key_hex: share.public_key_hex,
        raw_share: share.raw_share,
        participants: JSON.parse(share.participants_json),
      },
      addresses: addresses.map(addr => ({
        chain: addr.chain,
        derivation_path: addr.derivation_path,
        address: addr.address,
        public_key_hex: addr.public_key_hex,
      })),
    };

    const encrypted = this.encrypt(JSON.stringify(exportData), password);
    return Buffer.from(encrypted, 'utf8');
  }

  /**
   * 导入 share
   */
  importShare(data: Buffer, password: string): ShareRecord {
    if (!this.db) throw new Error('Database not initialized');

    const encrypted = data.toString('utf8');
    const decrypted = this.decrypt(encrypted, password);
    const exportData = JSON.parse(decrypted);

    if (!exportData.version || !exportData.share) {
      throw new Error('Invalid export file format');
    }

    // 检查是否已存在
    const existing = this.queryOne<{ id: string }>(`
      SELECT id FROM shares WHERE session_id = ? AND party_id = ?
    `, [exportData.share.session_id, exportData.share.party_id]);

    if (existing) {
      throw new Error('Share already exists');
    }

    // 保存 share
    const share = this.saveShare({
      sessionId: exportData.share.session_id,
      walletName: exportData.share.wallet_name,
      partyId: exportData.share.party_id,
      partyIndex: exportData.share.party_index,
      thresholdT: exportData.share.threshold_t,
      thresholdN: exportData.share.threshold_n,
      publicKeyHex: exportData.share.public_key_hex,
      rawShare: exportData.share.raw_share,
      participants: exportData.share.participants,
    }, password);

    // 恢复派生地址
    if (exportData.addresses) {
      for (const addr of exportData.addresses) {
        this.saveDerivedAddress({
          shareId: share.id,
          chain: addr.chain,
          derivationPath: addr.derivation_path,
          address: addr.address,
          publicKeyHex: addr.public_key_hex,
        });
      }
    }

    return share;
  }

  /**
   * 关闭数据库连接
   */
  close(): void {
    if (this.db) {
      this.saveToFile();
      this.db.close();
      this.db = null;
    }
  }
}
