/**
 * 聊天记录导入与分析 IPC 处理器
 */

import { ipcMain, app, dialog } from 'electron'
import { getConversationCountsBySession } from '../ai/conversations'
import * as databaseCore from '../database/core'
import * as worker from '../worker/workerManager'
import * as parser from '../parser'
import { detectFormat, scanMultiChatFile, type ParseProgress } from '../parser'
import type { IpcContext } from './types'
import { CURRENT_SCHEMA_VERSION, getPendingMigrationInfos } from '../database/migrations'
import { exportSessionToTempFile, cleanupTempExportFiles } from '../merger'
import { t } from '../i18n'

/**
 * 注册聊天记录相关 IPC 处理器
 */
export function registerChatHandlers(ctx: IpcContext): void {
  const { win } = ctx

  // ==================== 数据库迁移 ====================

  /**
   * 检查是否需要数据库迁移
   */
  ipcMain.handle('chat:checkMigration', async () => {
    try {
      const result = databaseCore.checkMigrationNeeded()
      // 获取待执行的迁移信息（从最低版本开始）
      const pendingMigrations = getPendingMigrationInfos(result.lowestVersion)
      return {
        needsMigration: result.count > 0,
        count: result.count,
        currentVersion: CURRENT_SCHEMA_VERSION,
        pendingMigrations,
      }
    } catch (error) {
      console.error('[IpcMain] Migration check failed:', error)
      return { needsMigration: false, count: 0, currentVersion: CURRENT_SCHEMA_VERSION, pendingMigrations: [] }
    }
  })

  /**
   * 执行数据库迁移
   */
  ipcMain.handle('chat:runMigration', async () => {
    try {
      const result = databaseCore.migrateAllDatabases()
      return result
    } catch (error) {
      console.error('[IpcMain] Migration execution failed:', error)
      return { success: false, migratedCount: 0, error: String(error) }
    }
  })

  // ==================== 聊天记录导入与分析 ====================

  /**
   * 选择聊天记录文件
   */
  ipcMain.handle('chat:selectFile', async () => {
    try {
      const { canceled, filePaths } = await dialog.showOpenDialog({
        title: t('dialog.selectChatFile'),
        defaultPath: app.getPath('documents'),
        properties: ['openFile'],
        filters: [
          { name: t('dialog.chatRecords'), extensions: ['json', 'jsonl', 'txt'] },
          { name: t('dialog.allFiles'), extensions: ['*'] },
        ],
        buttonLabel: t('dialog.import'),
      })

      if (canceled || filePaths.length === 0) {
        return null
      }

      const filePath = filePaths[0]

      // 检测文件格式（使用流式检测，只读取文件开头）
      const formatFeature = detectFormat(filePath)
      const format = formatFeature?.name || null
      if (!format) {
        return { error: 'error.unrecognized_format' }
      }

      return { filePath, format }
    } catch (error) {
      console.error('[IpcMain] Error selecting file:', error)
      return { error: String(error) }
    }
  })

  /**
   * 导入聊天记录（流式版本）
   */
  ipcMain.handle('chat:import', async (_, filePath: string) => {
    try {
      // Send progress: detecting format (message not used by frontend, stage-based translation)
      win.webContents.send('chat:importProgress', {
        stage: 'detecting',
        progress: 5,
        message: '', // Frontend translates based on stage
      })

      // 使用流式导入（在 Worker 线程中执行）
      const result = await worker.streamImport(filePath, (progress: ParseProgress) => {
        // 转发进度到渲染进程
        win.webContents.send('chat:importProgress', {
          stage: progress.stage,
          progress: progress.percentage,
          message: progress.message,
          bytesRead: progress.bytesRead,
          totalBytes: progress.totalBytes,
          messagesProcessed: progress.messagesProcessed,
        })
      })

      if (result.success) {
        console.log('[IpcMain] Stream import successful, sessionId:', result.sessionId)
        return { success: true, sessionId: result.sessionId, diagnostics: result.diagnostics }
      } else {
        console.error('[IpcMain] Stream import failed:', result.error)
        win.webContents.send('chat:importProgress', {
          stage: 'error',
          progress: 0,
          message: result.error,
        })

        return { success: false, error: result.error, diagnostics: result.diagnostics }
      }
    } catch (error) {
      console.error('[IpcMain] Import failed:', error)

      win.webContents.send('chat:importProgress', {
        stage: 'error',
        progress: 0,
        message: String(error),
      })

      return { success: false, error: String(error) }
    }
  })

  /**
   * 检测文件格式（轻量级，仅返回格式 ID、名称和是否多聊天）
   */
  ipcMain.handle('chat:detectFormat', async (_, filePath: string) => {
    try {
      const formatFeature = detectFormat(filePath)
      if (!formatFeature) return null
      return {
        id: formatFeature.id,
        name: formatFeature.name,
        platform: formatFeature.platform,
        multiChat: formatFeature.multiChat || false,
      }
    } catch {
      return null
    }
  })

  /**
   * 扫描多聊天文件中的聊天列表（通用）
   * 自动检测格式并调用对应格式的 scanChats
   */
  ipcMain.handle('chat:scanMultiChatFile', async (_, filePath: string) => {
    try {
      const chats = await scanMultiChatFile(filePath)
      return { success: true, chats }
    } catch (error) {
      console.error('[IpcMain] Failed to scan multi-chat files:', error)
      return { success: false, error: String(error), chats: [] }
    }
  })

  /**
   * 导入聊天记录（带格式选项）
   * 用于多聊天格式等需要额外参数的场景（如指定 chatIndex）
   */
  ipcMain.handle('chat:importWithOptions', async (_, filePath: string, formatOptions: Record<string, unknown>) => {
    try {
      win.webContents.send('chat:importProgress', {
        stage: 'detecting',
        progress: 5,
        message: '',
      })

      const result = await worker.streamImport(
        filePath,
        (progress: ParseProgress) => {
          win.webContents.send('chat:importProgress', {
            stage: progress.stage,
            progress: progress.percentage,
            message: progress.message,
            bytesRead: progress.bytesRead,
            totalBytes: progress.totalBytes,
            messagesProcessed: progress.messagesProcessed,
          })
        },
        formatOptions
      )

      if (result.success) {
        console.log('[IpcMain] Stream import (with options) successful, sessionId:', result.sessionId)
        return { success: true, sessionId: result.sessionId, diagnostics: result.diagnostics }
      } else {
        console.error('[IpcMain] Stream import (with options) failed:', result.error)
        win.webContents.send('chat:importProgress', {
          stage: 'error',
          progress: 0,
          message: result.error,
        })
        return { success: false, error: result.error, diagnostics: result.diagnostics }
      }
    } catch (error) {
      console.error('[IpcMain] Import with options failed:', error)
      win.webContents.send('chat:importProgress', {
        stage: 'error',
        progress: 0,
        message: String(error),
      })
      return { success: false, error: String(error) }
    }
  })

  /**
   * 获取所有分析会话列表
   */
  ipcMain.handle('chat:getSessions', async () => {
    try {
      const sessions = await worker.getAllSessions()

      // 填充 AI 对话计数（AI 数据库在主进程管理）
      try {
        const aiCounts = getConversationCountsBySession()
        for (const session of sessions) {
          session.aiConversationCount = aiCounts.get(session.id) || 0
        }
      } catch {
        // AI 数据库未初始化时忽略
      }

      return sessions
    } catch (error) {
      console.error('[IpcMain] Error getting sessions:', error)
      return []
    }
  })

  /**
   * 获取单个会话信息
   */
  ipcMain.handle('chat:getSession', async (_, sessionId: string) => {
    try {
      return await worker.getSession(sessionId)
    } catch (error) {
      console.error('Failed to get session info:', error)
      return null
    }
  })

  /**
   * 删除会话
   */
  ipcMain.handle('chat:deleteSession', async (_, sessionId: string) => {
    try {
      await worker.closeDatabase(sessionId)
      const result = databaseCore.deleteSession(sessionId)
      return result
    } catch (error) {
      console.error('Failed to delete session:', error)
      return false
    }
  })

  /**
   * 重命名会话
   */
  ipcMain.handle('chat:renameSession', async (_, sessionId: string, newName: string) => {
    try {
      // 先关闭 Worker 中的数据库连接（确保没有其他进程占用）
      await worker.closeDatabase(sessionId)
      // 执行重命名
      return databaseCore.renameSession(sessionId, newName)
    } catch (error) {
      console.error('Failed to rename session:', error)
      return false
    }
  })

  /**
   * 获取可用年份列表
   */
  ipcMain.handle('chat:getAvailableYears', async (_, sessionId: string) => {
    try {
      return await worker.getAvailableYears(sessionId)
    } catch (error) {
      console.error('Failed to get available years:', error)
      return []
    }
  })

  /**
   * 获取成员活跃度排行
   */
  ipcMain.handle(
    'chat:getMemberActivity',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getMemberActivity(sessionId, filter)
      } catch (error) {
        console.error('Failed to get member activity:', error)
        return []
      }
    }
  )

  /**
   * 获取成员历史昵称
   */
  ipcMain.handle('chat:getMemberNameHistory', async (_, sessionId: string, memberId: number) => {
    try {
      return await worker.getMemberNameHistory(sessionId, memberId)
    } catch (error) {
      console.error('Failed to get member name history:', error)
      return []
    }
  })

  /**
   * 获取每小时活跃度分布
   */
  ipcMain.handle(
    'chat:getHourlyActivity',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getHourlyActivity(sessionId, filter)
      } catch (error) {
        console.error('Failed to get hourly activity:', error)
        return []
      }
    }
  )

  /**
   * 获取每日活跃度趋势
   */
  ipcMain.handle(
    'chat:getDailyActivity',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getDailyActivity(sessionId, filter)
      } catch (error) {
        console.error('Failed to get daily activity:', error)
        return []
      }
    }
  )

  /**
   * 获取星期活跃度分布
   */
  ipcMain.handle(
    'chat:getWeekdayActivity',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getWeekdayActivity(sessionId, filter)
      } catch (error) {
        console.error('Failed to get weekday activity:', error)
        return []
      }
    }
  )

  /**
   * 获取月份活跃度分布
   */
  ipcMain.handle(
    'chat:getMonthlyActivity',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getMonthlyActivity(sessionId, filter)
      } catch (error) {
        console.error('Failed to get monthly activity:', error)
        return []
      }
    }
  )

  /**
   * 获取年份活跃度分布
   */
  ipcMain.handle(
    'chat:getYearlyActivity',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getYearlyActivity(sessionId, filter)
      } catch (error) {
        console.error('Failed to get yearly activity:', error)
        return []
      }
    }
  )

  /**
   * 获取消息长度分布
   */
  ipcMain.handle(
    'chat:getMessageLengthDistribution',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getMessageLengthDistribution(sessionId, filter)
      } catch (error) {
        console.error('Failed to get message length distribution:', error)
        return []
      }
    }
  )

  /**
   * 获取消息类型分布
   */
  ipcMain.handle(
    'chat:getMessageTypeDistribution',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getMessageTypeDistribution(sessionId, filter)
      } catch (error) {
        console.error('Failed to get message type distribution:', error)
        return []
      }
    }
  )

  /**
   * 获取时间范围
   */
  ipcMain.handle('chat:getTimeRange', async (_, sessionId: string) => {
    try {
      return await worker.getTimeRange(sessionId)
    } catch (error) {
      console.error('Failed to get time range:', error)
      return null
    }
  })

  /**
   * 获取数据库存储目录
   */
  ipcMain.handle('chat:getDbDirectory', async () => {
    try {
      return worker.getDbDirectory()
    } catch (error) {
      console.error('Failed to get database directory:', error)
      return null
    }
  })

  /**
   * 获取支持的格式列表
   */
  ipcMain.handle('chat:getSupportedFormats', async () => {
    return parser.getSupportedFormats()
  })

  /**
   * 获取口头禅分析数据
   */
  ipcMain.handle(
    'chat:getCatchphraseAnalysis',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getCatchphraseAnalysis(sessionId, filter)
      } catch (error) {
        console.error('Failed to get catchphrase analysis:', error)
        return { members: [] }
      }
    }
  )

  /**
   * 获取语言偏好分析数据（私聊专用）
   */
  ipcMain.handle(
    'chat:getLanguagePreferenceAnalysis',
    async (_, sessionId: string, locale: string, filter?: { startTs?: number; endTs?: number }, dictType?: string) => {
      try {
        return await worker.getLanguagePreferenceAnalysis({ sessionId, locale, timeFilter: filter, dictType })
      } catch (error) {
        console.error('Failed to get language preference analysis:', error)
        return { members: [], sharedWords: [], similarityScore: 0 }
      }
    }
  )

  /**
   * 获取 @ 互动分析数据
   */
  ipcMain.handle(
    'chat:getMentionAnalysis',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getMentionAnalysis(sessionId, filter)
      } catch (error) {
        console.error('Failed to get @mention analysis:', error)
        return { topMentioners: [], topMentioned: [], oneWay: [], twoWay: [], totalMentions: 0, memberDetails: [] }
      }
    }
  )

  /**
   * 获取 @ 互动关系图数据
   */
  ipcMain.handle(
    'chat:getMentionGraph',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }) => {
      try {
        return await worker.getMentionGraph(sessionId, filter)
      } catch (error) {
        console.error('Failed to get @mention graph:', error)
        return { nodes: [], links: [], maxLinkValue: 0 }
      }
    }
  )

  /**
   * 获取小团体关系图数据（基于时间相邻共现）
   */
  ipcMain.handle(
    'chat:getClusterGraph',
    async (
      _,
      sessionId: string,
      filter?: { startTs?: number; endTs?: number },
      options?: {
        lookAhead?: number
        decaySeconds?: number
        minScore?: number
        topEdges?: number
      }
    ) => {
      try {
        return await worker.getClusterGraph(sessionId, filter, options)
      } catch (error) {
        console.error('Failed to get clique graph:', error)
        return {
          nodes: [],
          links: [],
          maxLinkValue: 0,
          communities: [],
          stats: {
            totalMembers: 0,
            totalMessages: 0,
            involvedMembers: 0,
            edgeCount: 0,
            communityCount: 0,
          },
        }
      }
    }
  )

  /**
   * 获取含笑量分析数据
   */
  ipcMain.handle(
    'chat:getLaughAnalysis',
    async (_, sessionId: string, filter?: { startTs?: number; endTs?: number }, keywords?: string[]) => {
      try {
        return await worker.getLaughAnalysis(sessionId, filter, keywords)
      } catch (error) {
        console.error('Failed to get humor analysis:', error)
        return {
          rankByRate: [],
          rankByCount: [],
          typeDistribution: [],
          totalLaughs: 0,
          totalMessages: 0,
          groupLaughRate: 0,
        }
      }
    }
  )

  /**
   * 获取关系主动性分析数据（私聊专属）
   */
  ipcMain.handle(
    'chat:getRelationshipStats',
    async (
      _,
      sessionId: string,
      filter?: { startTs?: number; endTs?: number },
      options?: { perseveranceThreshold?: number }
    ) => {
      try {
        return await worker.getRelationshipStats(sessionId, filter, options)
      } catch (error) {
        console.error('Failed to get relationship stats:', error)
        return { months: [], members: [], totalSessions: 0, hasSessionIndex: false }
      }
    }
  )

  // ==================== 成员管理 ====================

  /**
   * 获取所有成员列表（含消息数和别名）
   */
  ipcMain.handle('chat:getMembers', async (_, sessionId: string) => {
    try {
      return await worker.getMembers(sessionId)
    } catch (error) {
      console.error('Failed to get member list:', error)
      return []
    }
  })

  /**
   * 获取成员列表（分页版本）
   */
  ipcMain.handle(
    'chat:getMembersPaginated',
    async (
      _,
      sessionId: string,
      params: { page: number; pageSize: number; search?: string; sortOrder?: 'asc' | 'desc' }
    ) => {
      try {
        return await worker.getMembersPaginated(sessionId, params)
      } catch (error) {
        console.error('Failed to get member list (paginated):', error)
        return { members: [], total: 0, page: 1, pageSize: 20, totalPages: 0 }
      }
    }
  )

  /**
   * 更新成员别名
   */
  ipcMain.handle('chat:updateMemberAliases', async (_, sessionId: string, memberId: number, aliases: string[]) => {
    try {
      const result = await worker.updateMemberAliases(sessionId, memberId, aliases)
      if (result) worker.invalidateAnalysisCache(sessionId).catch(() => {})
      return result
    } catch (error) {
      console.error('Failed to update member alias:', error)
      return false
    }
  })

  /**
   * 合并成员（保留消息数更多的一方）
   */
  ipcMain.handle('chat:mergeMembers', async (_, sessionId: string, memberId1: number, memberId2: number) => {
    try {
      await worker.closeDatabase(sessionId)
      const result = await worker.mergeMembers(sessionId, memberId1, memberId2)
      if (result) worker.invalidateAnalysisCache(sessionId).catch(() => {})
      return result
    } catch (error) {
      console.error('Failed to merge members:', error)
      return false
    }
  })

  /**
   * 删除成员及其所有消息
   */
  ipcMain.handle('chat:deleteMember', async (_, sessionId: string, memberId: number) => {
    try {
      // 先关闭数据库连接
      await worker.closeDatabase(sessionId)
      // 执行删除
      const result = await worker.deleteMember(sessionId, memberId)
      if (result) worker.invalidateAnalysisCache(sessionId).catch(() => {})
      return result
    } catch (error) {
      console.error('Failed to delete member:', error)
      return false
    }
  })

  /**
   * 更新会话的所有者（ownerId）
   */
  ipcMain.handle('chat:updateSessionOwnerId', async (_, sessionId: string, ownerId: string | null) => {
    try {
      // 先关闭数据库连接
      await worker.closeDatabase(sessionId)
      // 执行更新
      return databaseCore.updateSessionOwnerId(sessionId, ownerId)
    } catch (error) {
      console.error('Failed to update session owner:', error)
      return false
    }
  })

  // ==================== 插件系统 ====================

  /**
   * 插件参数化只读 SQL 查询
   */
  ipcMain.handle('chat:pluginQuery', async (_, sessionId: string, sql: string, params: any[]) => {
    try {
      return await worker.pluginQuery(sessionId, sql, params)
    } catch (error) {
      console.error('[IpcMain] Plugin query failed:', error)
      throw error
    }
  })

  /**
   * 插件计算卸载（纯函数在 Worker 中执行）
   */
  ipcMain.handle('chat:pluginCompute', async (_, fnString: string, input: any) => {
    try {
      return await worker.pluginCompute(fnString, input)
    } catch (error) {
      console.error('[IpcMain] Plugin compute failed:', error)
      throw error
    }
  })

  // ==================== SQL 实验室 ====================

  /**
   * 执行用户 SQL 查询
   */
  ipcMain.handle('chat:executeSQL', async (_, sessionId: string, sql: string) => {
    try {
      return await worker.executeRawSQL(sessionId, sql)
    } catch (error) {
      console.error('Failed to execute SQL:', error)
      throw error
    }
  })

  /**
   * 获取数据库 Schema
   */
  ipcMain.handle('chat:getSchema', async (_, sessionId: string) => {
    try {
      return await worker.getSchema(sessionId)
    } catch (error) {
      console.error('Failed to get schema:', error)
      return []
    }
  })

  // ==================== 会话索引 ====================

  /**
   * 生成会话索引
   */
  ipcMain.handle('session:generate', async (_, sessionId: string, gapThreshold?: number) => {
    try {
      return await worker.generateSessions(sessionId, gapThreshold)
    } catch (error) {
      console.error('Failed to generate session index:', error)
      throw error
    }
  })

  /**
   * 检查是否已生成会话索引
   */
  ipcMain.handle('session:hasIndex', async (_, sessionId: string) => {
    try {
      return await worker.hasSessionIndex(sessionId)
    } catch (error) {
      console.error('Failed to check session index:', error)
      return false
    }
  })

  /**
   * 获取会话索引统计信息
   */
  ipcMain.handle('session:getStats', async (_, sessionId: string) => {
    try {
      return await worker.getSessionStats(sessionId)
    } catch (error) {
      console.error('Failed to get session stats:', error)
      return { sessionCount: 0, hasIndex: false, gapThreshold: 1800 }
    }
  })

  /**
   * 清空会话索引
   */
  ipcMain.handle('session:clear', async (_, sessionId: string) => {
    try {
      await worker.clearSessions(sessionId)
      return true
    } catch (error) {
      console.error('Failed to clear session index:', error)
      return false
    }
  })

  /**
   * 更新会话切分阈值
   */
  ipcMain.handle('session:updateGapThreshold', async (_, sessionId: string, gapThreshold: number | null) => {
    try {
      await worker.updateSessionGapThreshold(sessionId, gapThreshold)
      return true
    } catch (error) {
      console.error('Failed to update threshold:', error)
      return false
    }
  })

  /**
   * 获取会话列表（用于时间线导航）
   */
  ipcMain.handle('session:getSessions', async (_, sessionId: string) => {
    try {
      return await worker.getSessions(sessionId)
    } catch (error) {
      console.error('Failed to get session list:', error)
      return []
    }
  })

  // ==================== 会话摘要 ====================

  /**
   * 生成单个会话摘要
   */
  ipcMain.handle(
    'session:generateSummary',
    async (_, dbSessionId: string, chatSessionId: number, locale?: string, forceRegenerate?: boolean) => {
      console.log('[IPC] session:generateSummary request received:', {
        dbSessionId,
        chatSessionId,
        locale,
        forceRegenerate,
      })
      try {
        const { generateSessionSummary } = await import('../ai/summary')
        const result = await generateSessionSummary(
          dbSessionId,
          chatSessionId,
          locale || 'zh-CN',
          forceRegenerate || false
        )
        console.log('[IPC] session:generateSummary result:', result)
        return result
      } catch (error) {
        console.error('[IPC] Failed to generate session summary:', error)
        return { success: false, error: String(error) }
      }
    }
  )

  /**
   * 批量生成会话摘要
   */
  ipcMain.handle(
    'session:generateSummaries',
    async (_, dbSessionId: string, chatSessionIds: number[], locale?: string) => {
      try {
        const { generateSessionSummaries } = await import('../ai/summary')
        return await generateSessionSummaries(dbSessionId, chatSessionIds, locale || 'zh-CN')
      } catch (error) {
        console.error('Failed to batch generate session summaries:', error)
        return { success: 0, failed: chatSessionIds.length, skipped: 0 }
      }
    }
  )

  /**
   * 批量检查会话是否可以生成摘要
   */
  ipcMain.handle('session:checkCanGenerateSummary', async (_, dbSessionId: string, chatSessionIds: number[]) => {
    try {
      const { checkSessionsCanGenerateSummary } = await import('../ai/summary')
      const results = checkSessionsCanGenerateSummary(dbSessionId, chatSessionIds)
      // 将 Map 转换为普通对象以便 IPC 传输
      const obj: Record<number, { canGenerate: boolean; reason?: string }> = {}
      for (const [id, result] of results) {
        obj[id] = result
      }
      return obj
    } catch (error) {
      console.error('Failed to batch check session summaries:', error)
      return {}
    }
  })

  /**
   * 根据时间范围查询会话列表
   */
  ipcMain.handle('session:getByTimeRange', async (_, dbSessionId: string, startTs: number, endTs: number) => {
    console.log('[session:getByTimeRange] Query params:', { dbSessionId, startTs, endTs })
    console.log('[session:getByTimeRange] Time range:', {
      start: new Date(startTs * 1000).toISOString(),
      end: new Date(endTs * 1000).toISOString(),
    })

    try {
      const db = databaseCore.openDatabase(dbSessionId, true)
      if (!db) {
        console.log('[session:getByTimeRange] Failed to open database')
        return []
      }

      // 先查询总数和时间范围
      const stats = db
        .prepare('SELECT COUNT(*) as count, MIN(start_ts) as minTs, MAX(start_ts) as maxTs FROM chat_session')
        .get() as { count: number; minTs: number; maxTs: number }
      console.log('[session:getByTimeRange] Database session stats:', {
        count: stats.count,
        minTs: stats.minTs ? new Date(stats.minTs * 1000).toISOString() : null,
        maxTs: stats.maxTs ? new Date(stats.maxTs * 1000).toISOString() : null,
      })

      const sessions = db
        .prepare(
          `
            SELECT
              id,
              start_ts as startTs,
              end_ts as endTs,
              message_count as messageCount,
              summary
            FROM chat_session
            WHERE start_ts >= ? AND start_ts <= ?
            ORDER BY start_ts DESC
          `
        )
        .all(startTs, endTs) as Array<{
        id: number
        startTs: number
        endTs: number
        messageCount: number
        summary: string | null
      }>

      console.log('[session:getByTimeRange] Query result count:', sessions.length)
      return sessions
    } catch (error) {
      console.error('Failed to query sessions by time range:', error)
      return []
    }
  })

  /**
   * 获取最近 N 条会话
   */
  ipcMain.handle('session:getRecent', async (_, dbSessionId: string, limit: number) => {
    console.log('[session:getRecent] Query params:', { dbSessionId, limit })
    try {
      const db = databaseCore.openDatabase(dbSessionId, true)
      if (!db) {
        console.log('[session:getRecent] Failed to open database')
        return []
      }

      // 先检查表是否存在
      const tableInfo = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='chat_session'").get()
      console.log('[session:getRecent] chat_session table:', tableInfo ? 'exists' : 'not exists')

      if (!tableInfo) {
        return []
      }

      const sessions = db
        .prepare(
          `
          SELECT
            id,
            start_ts as startTs,
            end_ts as endTs,
            message_count as messageCount,
            summary
          FROM chat_session
          ORDER BY start_ts DESC
          LIMIT ?
        `
        )
        .all(limit) as Array<{
        id: number
        startTs: number
        endTs: number
        messageCount: number
        summary: string | null
      }>

      console.log('[session:getRecent] Query result count:', sessions.length)
      return sessions
    } catch (error) {
      console.error('Failed to query recent sessions:', error)
      return []
    }
  })

  // ==================== 增量导入 ====================

  /**
   * 分析增量导入（检测去重后能新增多少消息）
   */
  ipcMain.handle('chat:analyzeIncrementalImport', async (_, sessionId: string, filePath: string) => {
    try {
      // 检测文件格式
      const formatFeature = detectFormat(filePath)
      if (!formatFeature) {
        return { error: 'error.unrecognized_format' }
      }

      // 使用 Worker 分析
      const result = await worker.analyzeIncrementalImport(sessionId, filePath)
      return result
    } catch (error) {
      console.error('[IpcMain] Failed to analyze incremental import:', error)
      return { error: String(error) }
    }
  })

  /**
   * 执行增量导入
   */
  ipcMain.handle('chat:incrementalImport', async (_, sessionId: string, filePath: string) => {
    try {
      // 发送进度
      win.webContents.send('chat:importProgress', {
        stage: 'saving',
        progress: 0,
        message: '',
      })

      const result = await worker.incrementalImport(sessionId, filePath, (progress) => {
        win.webContents.send('chat:importProgress', {
          stage: progress.stage,
          progress: progress.percentage,
          message: progress.message,
        })
      })

      if (result.success) {
        // 增量生成会话索引（仅处理新增消息，保留已有会话和摘要）
        try {
          await worker.generateIncrementalSessions(sessionId)
        } catch (e) {
          console.error('[IpcMain] Failed to incrementally generate session index:', e)
        }
        // 数据变更后清除分析缓存
        worker.invalidateAnalysisCache(sessionId).catch(() => {})
      }

      return result
    } catch (error) {
      console.error('[IpcMain] Failed to execute incremental import:', error)
      return { success: false, error: String(error) }
    }
  })

  // ==================== 批量管理：导出会话为临时文件 ====================

  /**
   * 导出多个会话为临时文件（用于合并）
   */
  ipcMain.handle('chat:exportSessionsToTempFiles', async (_, sessionIds: string[]) => {
    try {
      const tempFiles: string[] = []
      for (const sessionId of sessionIds) {
        const tempPath = await exportSessionToTempFile(sessionId)
        tempFiles.push(tempPath)
      }
      return { success: true, tempFiles }
    } catch (error) {
      console.error('[IpcMain] Failed to export session:', error)
      return { success: false, error: String(error), tempFiles: [] }
    }
  })

  /**
   * 清理临时导出文件
   */
  ipcMain.handle('chat:cleanupTempExportFiles', async (_, filePaths: string[]) => {
    try {
      cleanupTempExportFiles(filePaths)
      return { success: true }
    } catch (error) {
      console.error('[IpcMain] Failed to clean up temp files:', error)
      return { success: false, error: String(error) }
    }
  })
}
