/**
 * 临时数据库缓存管理器
 * 用于合并功能：将解析结果存入临时 SQLite 数据库，避免内存溢出
 */

import Database from 'better-sqlite3'
import * as fs from 'fs'
import * as path from 'path'
import { app } from 'electron'
import type { ParseResult, ParsedMeta, ParsedMember, ParsedMessage } from '../../../src/types/chat'

// 临时数据库目录
let tempDir: string | null = null

/**
 * 获取临时数据库目录
 */
function getTempDir(): string {
  if (tempDir) return tempDir

  try {
    const docPath = app.getPath('documents')
    tempDir = path.join(docPath, 'ChatLab', 'temp')
  } catch (error) {
    console.error('[TempCache] Error getting documents path:', error)
    tempDir = path.join(process.cwd(), 'temp')
  }

  // 确保目录存在
  if (!fs.existsSync(tempDir)) {
    fs.mkdirSync(tempDir, { recursive: true })
  }

  return tempDir
}

/**
 * 生成临时数据库文件路径
 */
export function generateTempDbPath(sourceFilePath: string): string {
  const timestamp = Date.now()
  const random = Math.random().toString(36).substring(2, 8)
  const baseName = path.basename(sourceFilePath, path.extname(sourceFilePath))
  const safeName = baseName.replace(/[/\\?%*:|"<>]/g, '_').substring(0, 50)
  return path.join(getTempDir(), `merge_${safeName}_${timestamp}_${random}.db`)
}

/**
 * 创建临时数据库并初始化表结构
 */
export function createTempDatabase(dbPath: string): Database.Database {
  const db = new Database(dbPath)

  db.pragma('journal_mode = WAL')
  db.pragma('synchronous = NORMAL')

  db.exec(`
    CREATE TABLE IF NOT EXISTS meta (
      name TEXT NOT NULL,
      platform TEXT NOT NULL,
      type TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS member (
      platform_id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      nickname TEXT
    );

    CREATE TABLE IF NOT EXISTS message (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      sender_platform_id TEXT NOT NULL,
      sender_name TEXT NOT NULL,
      timestamp INTEGER NOT NULL,
      type INTEGER NOT NULL,
      content TEXT
    );

    CREATE INDEX IF NOT EXISTS idx_message_ts ON message(timestamp);
    CREATE INDEX IF NOT EXISTS idx_message_sender ON message(sender_platform_id);
  `)

  return db
}

/**
 * 临时数据库写入器
 * 用于流式写入解析结果
 */
export class TempDbWriter {
  private db: Database.Database
  private insertMeta: Database.Statement
  private insertMember: Database.Statement
  private insertMessage: Database.Statement
  private memberSet: Set<string> = new Set()
  private messageCount: number = 0

  constructor(dbPath: string) {
    this.db = createTempDatabase(dbPath)

    // 准备语句
    this.insertMeta = this.db.prepare(`
      INSERT INTO meta (name, platform, type) VALUES (?, ?, ?)
    `)
    this.insertMember = this.db.prepare(`
      INSERT OR IGNORE INTO member (platform_id, name, nickname) VALUES (?, ?, ?)
    `)
    this.insertMessage = this.db.prepare(`
      INSERT INTO message (sender_platform_id, sender_name, timestamp, type, content)
      VALUES (?, ?, ?, ?, ?)
    `)

    // 开始事务
    this.db.exec('BEGIN TRANSACTION')
  }

  /**
   * 写入元信息
   */
  writeMeta(meta: ParsedMeta): void {
    this.insertMeta.run(meta.name, meta.platform, meta.type)
  }

  /**
   * 写入成员（批量）
   */
  writeMembers(members: ParsedMember[]): void {
    for (const m of members) {
      if (!this.memberSet.has(m.platformId)) {
        this.memberSet.add(m.platformId)
        this.insertMember.run(m.platformId, m.name, m.nickname || null)
      }
    }
  }

  /**
   * 写入消息（批量）
   */
  writeMessages(messages: ParsedMessage[]): void {
    for (const msg of messages) {
      // 确保成员存在
      if (!this.memberSet.has(msg.senderPlatformId)) {
        this.memberSet.add(msg.senderPlatformId)
        this.insertMember.run(msg.senderPlatformId, msg.senderName, null)
      }

      this.insertMessage.run(msg.senderPlatformId, msg.senderName, msg.timestamp, msg.type, msg.content || null)
      this.messageCount++
    }
  }

  /**
   * 完成写入（提交事务）
   */
  finish(): { messageCount: number; memberCount: number } {
    this.db.exec('COMMIT')
    const result = {
      messageCount: this.messageCount,
      memberCount: this.memberSet.size,
    }
    this.db.close()
    return result
  }

  /**
   * 取消写入（回滚事务）
   */
  abort(): void {
    try {
      this.db.exec('ROLLBACK')
    } catch {
      // 忽略回滚错误
    }
    this.db.close()
  }
}

/**
 * 临时数据库读取器
 * 用于流式读取合并时的数据
 */
export class TempDbReader {
  private db: Database.Database
  private dbPath: string

  constructor(dbPath: string) {
    this.dbPath = dbPath
    this.db = new Database(dbPath, { readonly: true })
    this.db.pragma('journal_mode = WAL')
  }

  /**
   * 读取元信息
   */
  getMeta(): ParsedMeta | null {
    const row = this.db.prepare('SELECT * FROM meta LIMIT 1').get() as
      | { name: string; platform: string; type: string }
      | undefined
    if (!row) return null
    return {
      name: row.name,
      platform: row.platform,
      type: row.type as 'group' | 'private',
    }
  }

  /**
   * 读取所有成员
   */
  getMembers(): ParsedMember[] {
    const rows = this.db.prepare('SELECT * FROM member').all() as Array<{
      platform_id: string
      name: string
      nickname: string | null
    }>
    return rows.map((r) => ({
      platformId: r.platform_id,
      name: r.name,
      nickname: r.nickname || undefined,
    }))
  }

  /**
   * 获取消息总数
   */
  getMessageCount(): number {
    const row = this.db.prepare('SELECT COUNT(*) as count FROM message').get() as { count: number }
    return row.count
  }

  /**
   * 流式读取消息（分批）
   * @param batchSize 每批消息数量
   * @param callback 处理每批消息的回调
   */
  streamMessages(batchSize: number, callback: (messages: ParsedMessage[]) => void): void {
    const stmt = this.db.prepare(`
      SELECT sender_platform_id, sender_name, timestamp, type, content
      FROM message
      ORDER BY timestamp ASC
      LIMIT ? OFFSET ?
    `)

    let offset = 0
    while (true) {
      const rows = stmt.all(batchSize, offset) as Array<{
        sender_platform_id: string
        sender_name: string
        timestamp: number
        type: number
        content: string | null
      }>

      if (rows.length === 0) break

      const messages: ParsedMessage[] = rows.map((r) => ({
        senderPlatformId: r.sender_platform_id,
        senderName: r.sender_name,
        timestamp: r.timestamp,
        type: r.type,
        content: r.content || undefined,
      }))

      callback(messages)
      offset += batchSize
    }
  }

  /**
   * 获取所有消息（用于冲突检测，内存中处理）
   * 注意：对于超大文件，应使用 streamMessages
   */
  getAllMessages(): ParsedMessage[] {
    const rows = this.db
      .prepare(
        `
      SELECT sender_platform_id, sender_name, timestamp, type, content
      FROM message
      ORDER BY timestamp ASC
    `
      )
      .all() as Array<{
      sender_platform_id: string
      sender_name: string
      timestamp: number
      type: number
      content: string | null
    }>

    return rows.map((r) => ({
      senderPlatformId: r.sender_platform_id,
      senderName: r.sender_name,
      timestamp: r.timestamp,
      type: r.type,
      content: r.content || undefined,
    }))
  }

  /**
   * 关闭数据库连接
   */
  close(): void {
    this.db.close()
  }

  /**
   * 获取数据库路径
   */
  getPath(): string {
    return this.dbPath
  }
}

/**
 * 删除临时数据库文件
 */
export function deleteTempDatabase(dbPath: string): void {
  try {
    const walPath = dbPath + '-wal'
    const shmPath = dbPath + '-shm'

    if (fs.existsSync(dbPath)) fs.unlinkSync(dbPath)
    if (fs.existsSync(walPath)) fs.unlinkSync(walPath)
    if (fs.existsSync(shmPath)) fs.unlinkSync(shmPath)

    console.log(`[TempCache] 已删除临时数据库: ${dbPath}`)
  } catch (error) {
    console.error(`[TempCache] 删除临时数据库失败: ${dbPath}`, error)
  }
}

/**
 * 清理所有临时数据库（应用启动时调用）
 */
export function cleanupAllTempDatabases(): void {
  try {
    const dir = getTempDir()
    if (!fs.existsSync(dir)) return

    const files = fs.readdirSync(dir)
    for (const file of files) {
      if (file.startsWith('merge_') && file.endsWith('.db')) {
        const filePath = path.join(dir, file)
        deleteTempDatabase(filePath)
      }
    }
    console.log('[TempCache] 已清理所有临时数据库')
  } catch (error) {
    console.error('[TempCache] 清理临时数据库失败:', error)
  }
}
