/**
 * 本地数据库服务
 * 使用 SQLite 存储聊天记录
 * 每个用户使用独立的数据库文件，避免数据串用
 */

import * as SQLite from 'expo-sqlite';
import type {
  UserDTO,
  GroupResponse,
  GroupMemberResponse,
  ConversationResponse,
  ConversationDetailResponse,
} from '../types/dto';

// 数据库实例
let db: SQLite.SQLiteDatabase | null = null;
let writeQueue: Promise<void> = Promise.resolve();

// 当前数据库对应的用户ID
let currentDbUserId: string | null = null;

/**
 * 串行化 open/close，避免并发 initDatabase（如 React Strict Mode 双次 effect、登录与冷启动校验交错）
 * 导致后完成的 open 覆盖先完成的连接，进而在 Android 上出现 NativeDatabase.execAsync NPE。
 */
let dbOpenCloseMutex: Promise<void> = Promise.resolve();

async function withDbOpenCloseLock<T>(fn: () => Promise<T>): Promise<T> {
  const previous = dbOpenCloseMutex;
  let release!: () => void;
  dbOpenCloseMutex = new Promise<void>((resolve) => {
    release = resolve;
  });
  try {
    await previous;
    return await fn();
  } finally {
    release();
  }
}

// 数据库版本，用于迁移
const DB_VERSION = 2;

/** 关闭连接（须在已持有 dbOpenCloseMutex 时调用，或作为 withDbOpenCloseLock 内的实现） */
const closeDatabaseUnlocked = async (): Promise<void> => {
  if (db) {
    try {
      await db.closeAsync();
    } catch (error) {
      console.error('[Database] 关闭数据库失败:', error);
    }
    db = null;
    currentDbUserId = null;
  }
};

async function initDatabaseUnlocked(userId?: string): Promise<void> {
  // 如果指定了用户ID，使用用户专属数据库
  // 否则使用默认数据库（兼容旧版本）
  const dbName = userId ? `carrot_bbs_${userId}.db` : 'carrot_bbs.db';

  // 如果存在旧的数据库连接且用户ID变化，需要关闭旧连接
  if (db && currentDbUserId !== userId) {
    await closeDatabaseUnlocked();
  }

  // 如果已经打开了正确的数据库，直接返回
  if (db && currentDbUserId === userId) {
    return;
  }

  let opened: SQLite.SQLiteDatabase | null = null;
  try {
    opened = await SQLite.openDatabaseAsync(dbName);
    db = opened;
    currentDbUserId = userId || null;
    
    // 创建消息表（包含新字段 seq, status, segments）
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS messages (
        id TEXT PRIMARY KEY NOT NULL,
        conversationId TEXT NOT NULL,
        senderId TEXT NOT NULL,
        content TEXT,
        type TEXT DEFAULT 'text',
        isRead INTEGER DEFAULT 0,
        createdAt TEXT NOT NULL,
        seq INTEGER DEFAULT 0,
        status TEXT DEFAULT 'normal',
        segments TEXT
      );
    `);
    
    // 创建会话表
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS conversations (
        id TEXT PRIMARY KEY NOT NULL,
        participantId TEXT NOT NULL,
        lastMessageId TEXT,
        lastSeq INTEGER DEFAULT 0,
        unreadCount INTEGER DEFAULT 0,
        createdAt TEXT NOT NULL,
        updatedAt TEXT NOT NULL
      );
    `);

    // 会话缓存表（完整 JSON，兼容私聊/群聊不同结构）
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS conversation_cache (
        id TEXT PRIMARY KEY NOT NULL,
        data TEXT NOT NULL,
        updatedAt TEXT NOT NULL
      );
    `);

    // 会话列表缓存表（仅用于 ChatList，避免被详情缓存污染）
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS conversation_list_cache (
        id TEXT PRIMARY KEY NOT NULL,
        data TEXT NOT NULL,
        updatedAt TEXT NOT NULL
      );
    `);

    // 用户缓存表
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS users (
        id TEXT PRIMARY KEY NOT NULL,
        data TEXT NOT NULL,
        updatedAt TEXT NOT NULL
      );
    `);

    // 当前登录用户缓存（仅保存 me）
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS current_user_cache (
        id TEXT PRIMARY KEY NOT NULL,
        data TEXT NOT NULL,
        updatedAt TEXT NOT NULL
      );
    `);

    // 群组缓存表
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS groups (
        id TEXT PRIMARY KEY NOT NULL,
        data TEXT NOT NULL,
        updatedAt TEXT NOT NULL
      );
    `);

    // 群成员缓存表
    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS group_members (
        groupId TEXT NOT NULL,
        userId TEXT NOT NULL,
        data TEXT NOT NULL,
        updatedAt TEXT NOT NULL,
        PRIMARY KEY (groupId, userId)
      );
    `);
    
    // 创建索引
    await db.execAsync(`
      CREATE INDEX IF NOT EXISTS idx_messages_conversationId ON messages(conversationId);
    `);
    await db.execAsync(`
      CREATE INDEX IF NOT EXISTS idx_group_members_groupId ON group_members(groupId);
    `);
    
    // 迁移：检查并添加新列（兼容旧版本数据库）
    await migrateDatabase();
    
    // 迁移后再创建依赖新列的索引
    await db.execAsync(`
      CREATE INDEX IF NOT EXISTS idx_messages_seq ON messages(seq);
    `);
    await db.execAsync(`
      CREATE INDEX IF NOT EXISTS idx_messages_conversation_seq ON messages(conversationId, seq);
    `);
  } catch (error) {
    console.error('数据库初始化失败:', error);
    try {
      if (opened && opened === db) {
        await opened.closeAsync();
      }
    } catch {
      /* ignore */
    }
    db = null;
    currentDbUserId = null;
    throw error;
  }
}

/**
 * 初始化用户数据库
 * @param userId 用户ID，用于创建用户专属数据库文件
 */
export const initDatabase = async (userId?: string): Promise<void> => {
  return withDbOpenCloseLock(() => initDatabaseUnlocked(userId));
};

/**
 * 关闭数据库连接
 */
export const closeDatabase = async (): Promise<void> => {
  return withDbOpenCloseLock(() => closeDatabaseUnlocked());
};

/**
 * 获取当前数据库用户ID
 */
export const getCurrentDbUserId = (): string | null => {
  return currentDbUserId;
};

// 数据库迁移
const migrateDatabase = async (): Promise<void> => {
  const database = await getDb();
  
  try {
    // 检查 messages 表是否有 seq 列
    const tableInfo = await database.getAllAsync<any>(
      `PRAGMA table_info(messages)`
    );
    
    const columns = tableInfo.map(col => col.name);
    
    // 添加 seq 列
    if (!columns.includes('seq')) {
      await database.execAsync(`ALTER TABLE messages ADD COLUMN seq INTEGER DEFAULT 0`);
    }
    
    // 添加 status 列
    if (!columns.includes('status')) {
      await database.execAsync(`ALTER TABLE messages ADD COLUMN status TEXT DEFAULT 'normal'`);
    }
    
    // 添加 segments 列（用于存储消息的 segments JSON）
    if (!columns.includes('segments')) {
      await database.execAsync(`ALTER TABLE messages ADD COLUMN segments TEXT`);
    }
    
    // 检查 conversations 表是否有 lastSeq 列
    const convTableInfo = await database.getAllAsync<any>(
      `PRAGMA table_info(conversations)`
    );
    const convColumns = convTableInfo.map(col => col.name);
    
    if (!convColumns.includes('lastSeq')) {
      await database.execAsync(`ALTER TABLE conversations ADD COLUMN lastSeq INTEGER DEFAULT 0`);
    }
  } catch (error) {
    console.error('数据库迁移失败:', error);
  }
};

// 获取数据库实例
const getDb = async (): Promise<SQLite.SQLiteDatabase> => {
  if (!db) {
    throw new Error('数据库未初始化，请先调用 initDatabase(userId)');
  }
  return db;
};

const isRecoverableDbError = (error: unknown): boolean => {
  const message = String(error);
  return (
    message.includes('NativeDatabase.prepareAsync') ||
    message.includes('NullPointerException') ||
    message.includes('Cannot use shared object that was already released') ||
    message.includes('NativeStatement')
  );
};

/** 在已持有 dbOpenCloseMutex 时重建连接（禁止在持有 SQLiteDatabase 期间 await 会抢锁的 recoverDbConnection） */
const reconnectDatabaseUnlocked = async (): Promise<void> => {
  await closeDatabaseUnlocked();
  await initDatabaseUnlocked(currentDbUserId || undefined);
};

/**
 * 读路径与 init/close/recover 共用同一把锁，避免：
 * 线程 A 持有 database 引用执行 prepareAsync 时，线程 B 的 recover 关闭连接导致 NPE。
 */
const withDbRead = async <T>(operation: (database: SQLite.SQLiteDatabase) => Promise<T>): Promise<T> => {
  return withDbOpenCloseLock(async () => {
    try {
      const database = await getDb();
      return await operation(database);
    } catch (error) {
      if (!isRecoverableDbError(error)) {
        throw error;
      }
      console.error('数据库读取异常，尝试重连后重试:', error);
      await reconnectDatabaseUnlocked();
      const database = await getDb();
      return await operation(database);
    }
  });
};

const enqueueWrite = async <T>(operation: () => Promise<T>): Promise<T> => {
  const wrappedOperation = async () => {
    return withDbOpenCloseLock(async () => {
      try {
        return await operation();
      } catch (error) {
        if (!isRecoverableDbError(error)) {
          throw error;
        }
        console.error('数据库写入异常，尝试重连后重试:', error);
        await reconnectDatabaseUnlocked();
        return await operation();
      }
    });
  };
  const queued = writeQueue.then(wrappedOperation, wrappedOperation);
  writeQueue = queued.then(() => undefined, () => undefined);
  return queued;
};

// ==================== 消息类型定义 ====================

export interface CachedMessage {
  id: string;
  conversationId: string;
  senderId: string;
  content?: string;
  type?: string;
  isRead: boolean;
  createdAt: string;
  seq: number;
  status: string;
  segments?: any;
}

// ==================== 消息操作 ====================

// 保存单条消息
export const saveMessage = async (message: CachedMessage): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `INSERT OR REPLACE INTO messages (id, conversationId, senderId, content, type, isRead, createdAt, seq, status, segments)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        message.id,
        message.conversationId,
        message.senderId,
        message.content || '',
        message.type || 'text',
        message.isRead ? 1 : 0,
        message.createdAt,
        message.seq || 0,
        message.status || 'normal',
        message.segments ? JSON.stringify(message.segments) : null,
      ]
    );
  });
};

// 批量保存消息
export const saveMessagesBatch = async (messages: CachedMessage[]): Promise<void> => {
  if (!messages || messages.length === 0) return;

  await enqueueWrite(async () => {
    const database = await getDb();
    for (const message of messages) {
      await database.runAsync(
        `INSERT OR REPLACE INTO messages (id, conversationId, senderId, content, type, isRead, createdAt, seq, status, segments)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          message.id,
          message.conversationId,
          message.senderId,
          message.content || '',
          message.type || 'text',
          message.isRead ? 1 : 0,
          message.createdAt,
          message.seq || 0,
          message.status || 'normal',
          message.segments ? JSON.stringify(message.segments) : null,
        ]
      );
    }
  });
};

// 获取会话的消息（默认只加载最近的20条，避免卡顿）
export const getMessagesByConversation = async (
  conversationId: string,
  limit: number = 20
): Promise<CachedMessage[]> => {
  return withDbRead(async (database) => {
    const result = await database.getAllAsync<any>(
      `SELECT * FROM messages
       WHERE conversationId = ?
       ORDER BY seq DESC
       LIMIT ?`,
      [conversationId, limit]
    );
    
    // 反转以保持时间正序（最新的在底部）
    return result.reverse().map(msg => ({
      ...msg,
      isRead: msg.isRead === 1,
      segments: msg.segments ? JSON.parse(msg.segments) : undefined,
    }));
  });
};

// 获取会话的最大消息序号
export const getMaxSeq = async (conversationId: string): Promise<number> => {
  return withDbRead(async (database) => {
    const result = await database.getFirstAsync<{ maxSeq: number }>(
      `SELECT MAX(seq) as maxSeq FROM messages WHERE conversationId = ?`,
      [conversationId]
    );
    
    return result?.maxSeq || 0;
  });
};

// 获取会话的最小消息序号
export const getMinSeq = async (conversationId: string): Promise<number> => {
  return withDbRead(async (database) => {
    const result = await database.getFirstAsync<{ minSeq: number }>(
      `SELECT MIN(seq) as minSeq FROM messages WHERE conversationId = ?`,
      [conversationId]
    );
    
    return result?.minSeq || 0;
  });
};

// 获取指定 seq 之前的消息（用于加载历史）
export const getMessagesBeforeSeq = async (conversationId: string, beforeSeq: number, limit: number = 20): Promise<CachedMessage[]> => {
  return withDbRead(async (database) => {
    const result = await database.getAllAsync<any>(
      `SELECT * FROM messages 
       WHERE conversationId = ? AND seq < ? 
       ORDER BY seq DESC 
       LIMIT ?`,
      [conversationId, beforeSeq, limit]
    );
    
    return result.map(msg => ({
      ...msg,
      isRead: msg.isRead === 1,
      segments: msg.segments ? JSON.parse(msg.segments) : undefined,
    })).reverse(); // 反转以保持时间正序
  });
};

// 获取本地消息数量（用于判断是否还有更多历史）
export const getLocalMessageCountBeforeSeq = async (conversationId: string, beforeSeq: number): Promise<number> => {
  return withDbRead(async (database) => {
    const result = await database.getFirstAsync<{ count: number }>(
      `SELECT COUNT(*) as count FROM messages WHERE conversationId = ? AND seq < ?`,
      [conversationId, beforeSeq]
    );
    return result?.count || 0;
  });
};

// 获取消息数量
export const getMessageCount = async (conversationId: string): Promise<number> => {
  return withDbRead(async (database) => {
    const result = await database.getFirstAsync<{ count: number }>(
      `SELECT COUNT(*) as count FROM messages WHERE conversationId = ?`,
      [conversationId]
    );
    return result?.count || 0;
  });
};

// 标记消息为已读
export const markMessageAsRead = async (messageId: string): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `UPDATE messages SET isRead = 1 WHERE id = ?`,
      [messageId]
    );
  });
};

// 标记会话的所有消息为已读
export const markConversationAsRead = async (conversationId: string): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `UPDATE messages SET isRead = 1 WHERE conversationId = ?`,
      [conversationId]
    );
  });
};

// 删除单条消息
export const deleteMessage = async (messageId: string): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `DELETE FROM messages WHERE id = ?`,
      [messageId]
    );
  });
};

// 更新消息状态（如撤回）
// clearContent=true 时，会同时清空本地存储的消息内容与 segments，仅保留状态占位
export const updateMessageStatus = async (
  messageId: string,
  status: string,
  clearContent: boolean = false
): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    if (clearContent) {
      await database.runAsync(
        `UPDATE messages SET status = ?, content = '', segments = '[]' WHERE id = ?`,
        [status, messageId]
      );
      return;
    }
    await database.runAsync(
      `UPDATE messages SET status = ? WHERE id = ?`,
      [status, messageId]
    );
  });
};

// 清空会话的所有消息
export const clearConversationMessages = async (conversationId: string): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `DELETE FROM messages WHERE conversationId = ?`,
      [conversationId]
    );
  });
};

// ==================== 会话操作 ====================

// 保存或更新会话
export const saveConversation = async (conversation: {
  id: string;
  participantId: string;
  lastMessageId?: string;
  lastSeq?: number;
  unreadCount?: number;
  createdAt: string;
  updatedAt: string;
}): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `INSERT OR REPLACE INTO conversations (id, participantId, lastMessageId, lastSeq, unreadCount, createdAt, updatedAt)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [
        conversation.id,
        conversation.participantId,
        conversation.lastMessageId || null,
        conversation.lastSeq || 0,
        conversation.unreadCount || 0,
        conversation.createdAt,
        conversation.updatedAt,
      ]
    );
  });
};

// 获取所有会话
export const getAllConversations = async (): Promise<any[]> => {
  return withDbRead(async (database) => {
    return database.getAllAsync<any>(`SELECT * FROM conversations ORDER BY updatedAt DESC`);
  });
};

// 更新会话未读数
export const updateConversationUnreadCount = async (conversationId: string, count: number): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `UPDATE conversations SET unreadCount = ? WHERE id = ?`,
      [count, conversationId]
    );
  });
};

// 更新会话最后消息
export const updateConversationLastMessage = async (
  conversationId: string, 
  lastMessageId: string, 
  lastSeq: number,
  updatedAt: string
): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `UPDATE conversations SET lastMessageId = ?, lastSeq = ?, updatedAt = ? WHERE id = ?`,
      [lastMessageId, lastSeq, updatedAt, conversationId]
    );
  });
};

// 删除会话（包含所有消息）
export const deleteConversation = async (conversationId: string): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `DELETE FROM messages WHERE conversationId = ?`,
      [conversationId]
    );
    await database.runAsync(
      `DELETE FROM conversations WHERE id = ?`,
      [conversationId]
    );
  });
};

// ==================== 搜索 ====================

// 搜索消息
export const searchMessages = async (keyword: string): Promise<CachedMessage[]> => {
  return withDbRead(async (database) => {
    const result = await database.getAllAsync<any>(
      `SELECT * FROM messages 
       WHERE content LIKE ? 
       ORDER BY createdAt DESC 
       LIMIT 50`,
      [`%${keyword}%`]
    );
    return result.map(msg => ({
      ...msg,
      isRead: msg.isRead === 1,
      segments: msg.segments ? JSON.parse(msg.segments) : undefined,
    }));
  });
};

// ==================== 工具函数 ====================

// 获取数据库统计信息
export const getDatabaseStats = async (): Promise<{
  totalMessages: number;
  totalConversations: number;
}> => {
  return withDbRead(async (database) => {
    const msgCount = await database.getFirstAsync<{ count: number }>(
      `SELECT COUNT(*) as count FROM messages`
    );
    const convCount = await database.getFirstAsync<{ count: number }>(
      `SELECT COUNT(*) as count FROM conversations`
    );
    return {
      totalMessages: msgCount?.count || 0,
      totalConversations: convCount?.count || 0,
    };
  });
};

// 清空所有数据（用于调试或用户退出登录）
export const clearAllData = async (): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.execAsync(`DELETE FROM messages`);
    await database.execAsync(`DELETE FROM conversations`);
    await database.execAsync(`DELETE FROM conversation_cache`);
    await database.execAsync(`DELETE FROM conversation_list_cache`);
    await database.execAsync(`DELETE FROM users`);
    await database.execAsync(`DELETE FROM current_user_cache`);
    await database.execAsync(`DELETE FROM groups`);
    await database.execAsync(`DELETE FROM group_members`);
  });
};

// ==================== 通用 JSON 缓存辅助 ====================

const safeParseJson = <T>(value: string): T | null => {
  try {
    return JSON.parse(value) as T;
  } catch {
    return null;
  }
};

// ==================== 用户缓存 ====================

export const saveUserCache = async (user: UserDTO): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `INSERT OR REPLACE INTO users (id, data, updatedAt) VALUES (?, ?, ?)`,
      [String(user.id), JSON.stringify(user), new Date().toISOString()]
    );
  });
};

export const saveUsersCache = async (users: UserDTO[]): Promise<void> => {
  if (!users || users.length === 0) return;
  await enqueueWrite(async () => {
    const database = await getDb();
    for (const user of users) {
      await database.runAsync(
        `INSERT OR REPLACE INTO users (id, data, updatedAt) VALUES (?, ?, ?)`,
        [String(user.id), JSON.stringify(user), new Date().toISOString()]
      );
    }
  });
};

export const getUserCache = async (userId: string): Promise<UserDTO | null> => {
  return withDbRead(async (database) => {
    const row = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM users WHERE id = ?`,
      [String(userId)]
    );
    if (!row?.data) return null;
    return safeParseJson<UserDTO>(row.data);
  });
};

export const getLatestUserCache = async (): Promise<UserDTO | null> => {
  return withDbRead(async (database) => {
    const row = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM users ORDER BY updatedAt DESC LIMIT 1`
    );
    if (!row?.data) return null;
    return safeParseJson<UserDTO>(row.data);
  });
};

export const saveCurrentUserCache = async (user: UserDTO): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `INSERT OR REPLACE INTO current_user_cache (id, data, updatedAt) VALUES (?, ?, ?)`,
      ['me', JSON.stringify(user), new Date().toISOString()]
    );
  });
};

export const getCurrentUserCache = async (): Promise<UserDTO | null> => {
  return withDbRead(async (database) => {
    const row = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM current_user_cache WHERE id = 'me'`
    );
    if (!row?.data) return null;
    return safeParseJson<UserDTO>(row.data);
  });
};

export const clearCurrentUserCache = async (): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(`DELETE FROM current_user_cache WHERE id = 'me'`);
  });
};

// ==================== 群组缓存 ====================

export const saveGroupCache = async (group: GroupResponse): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    await database.runAsync(
      `INSERT OR REPLACE INTO groups (id, data, updatedAt) VALUES (?, ?, ?)`,
      [String(group.id), JSON.stringify(group), new Date().toISOString()]
    );
  });
};

export const saveGroupsCache = async (groups: GroupResponse[]): Promise<void> => {
  if (!groups || groups.length === 0) return;
  await enqueueWrite(async () => {
    const database = await getDb();
    for (const group of groups) {
      await database.runAsync(
        `INSERT OR REPLACE INTO groups (id, data, updatedAt) VALUES (?, ?, ?)`,
        [String(group.id), JSON.stringify(group), new Date().toISOString()]
      );
    }
  });
};

export const getGroupCache = async (groupId: string): Promise<GroupResponse | null> => {
  return withDbRead(async (database) => {
    const row = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM groups WHERE id = ?`,
      [String(groupId)]
    );
    if (!row?.data) return null;
    return safeParseJson<GroupResponse>(row.data);
  });
};

export const getAllGroupsCache = async (): Promise<GroupResponse[]> => {
  return withDbRead(async (database) => {
    const rows = await database.getAllAsync<{ data: string }>(
      `SELECT data FROM groups ORDER BY updatedAt DESC`
    );
    return rows
      .map(row => safeParseJson<GroupResponse>(row.data))
      .filter((item): item is GroupResponse => Boolean(item));
  });
};

// ==================== 群成员缓存 ====================

export const saveGroupMembersCache = async (
  groupId: string,
  members: GroupMemberResponse[]
): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    const now = new Date().toISOString();
    await database.runAsync(`DELETE FROM group_members WHERE groupId = ?`, [String(groupId)]);
    for (const member of members) {
      await database.runAsync(
        `INSERT OR REPLACE INTO group_members (groupId, userId, data, updatedAt) VALUES (?, ?, ?, ?)`,
        [String(groupId), String(member.user_id), JSON.stringify(member), now]
      );
    }
  });
};

export const getGroupMembersCache = async (groupId: string): Promise<GroupMemberResponse[]> => {
  return withDbRead(async (database) => {
    const rows = await database.getAllAsync<{ data: string }>(
      `SELECT data FROM group_members WHERE groupId = ? ORDER BY updatedAt DESC`,
      [String(groupId)]
    );
    return rows
      .map(row => safeParseJson<GroupMemberResponse>(row.data))
      .filter((item): item is GroupMemberResponse => Boolean(item));
  });
};

// ==================== 会话缓存 ====================

type ConversationCacheData = ConversationResponse | ConversationDetailResponse;

export const saveConversationCache = async (conversation: ConversationCacheData): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    const cacheUpdatedAt = ('updated_at' in conversation && conversation.updated_at)
      ? String(conversation.updated_at)
      : new Date().toISOString();
    await database.runAsync(
      `INSERT OR REPLACE INTO conversation_cache (id, data, updatedAt) VALUES (?, ?, ?)`,
      [String(conversation.id), JSON.stringify(conversation), cacheUpdatedAt]
    );
  });
};

export const saveConversationsCache = async (conversations: ConversationResponse[]): Promise<void> => {
  if (!conversations || conversations.length === 0) return;
  await enqueueWrite(async () => {
    const database = await getDb();
    for (const conversation of conversations) {
      await database.runAsync(
        `INSERT OR REPLACE INTO conversation_list_cache (id, data, updatedAt) VALUES (?, ?, ?)`,
        [
          String(conversation.id),
          JSON.stringify(conversation),
          conversation.updated_at || new Date().toISOString(),
        ]
      );
    }
  });
};

export const getConversationCache = async (conversationId: string): Promise<ConversationCacheData | null> => {
  return withDbRead(async (database) => {
    const row = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM conversation_cache WHERE id = ?`,
      [String(conversationId)]
    );
    if (!row?.data) return null;
    return safeParseJson<ConversationCacheData>(row.data);
  });
};

export const getConversationListCache = async (): Promise<ConversationResponse[]> => {
  return withDbRead(async (database) => {
    let rows = await database.getAllAsync<{ data: string }>(
      `SELECT data FROM conversation_list_cache ORDER BY updatedAt DESC`
    );
    // 兼容旧版本：首次升级时尝试从旧表读取一次
    if (rows.length === 0) {
      rows = await database.getAllAsync<{ data: string }>(
        `SELECT data FROM conversation_cache ORDER BY updatedAt DESC`
      );
    }
    const list = rows
      .map(row => safeParseJson<ConversationResponse>(row.data))
      .filter((item): item is ConversationResponse => Boolean(item))
      .filter(item => typeof item.id !== 'undefined' && typeof item.type !== 'undefined');
    return list.sort((a, b) => {
      const aPinned = a.is_pinned ? 1 : 0;
      const bPinned = b.is_pinned ? 1 : 0;
      if (aPinned !== bPinned) {
        return bPinned - aPinned;
      }
      const aTime = new Date(a.last_message_at || a.updated_at || 0).getTime();
      const bTime = new Date(b.last_message_at || b.updated_at || 0).getTime();
      return bTime - aTime;
    });
  });
};

/**
 * 局部更新 conversation_list_cache 中的某条会话（如 last_message、last_message_at、unread_count 等）
 * 用于：发送消息后立即更新缓存中的最后一条消息，避免 SWR 返回旧数据
 */
export const updateConversationListCacheEntry = async (
  conversationId: string,
  updates: Partial<ConversationResponse>
): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();
    const row = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM conversation_list_cache WHERE id = ?`,
      [String(conversationId)]
    );
    if (!row?.data) return;
    const conv = safeParseJson<ConversationResponse>(row.data);
    if (!conv) return;
    const updated = { ...conv, ...updates };
    const updatedAt = updates.last_message_at || updated.last_message_at || new Date().toISOString();
    await database.runAsync(
      `UPDATE conversation_list_cache SET data = ?, updatedAt = ? WHERE id = ?`,
      [JSON.stringify(updated), updatedAt, String(conversationId)]
    );
  });
};

/**
 * 更新会话 SWR 缓存中的未读数（标记已读后立即同步清零，避免下次从缓存加载时仍显示旧红点）
 * @param myLastReadSeq 若传入，同时写入 my_last_read_seq，便于冷启动用 last_seq 与已读游标校正未读
 */
export const updateConversationCacheUnreadCount = async (
  conversationId: string,
  count: number,
  myLastReadSeq?: number
): Promise<void> => {
  await enqueueWrite(async () => {
    const database = await getDb();

    // 更新 conversation_list_cache
    const listRow = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM conversation_list_cache WHERE id = ?`,
      [String(conversationId)]
    );
    if (listRow?.data) {
      const conv = safeParseJson<ConversationResponse>(listRow.data);
      if (conv) {
        conv.unread_count = count;
        if (typeof myLastReadSeq === 'number' && !Number.isNaN(myLastReadSeq)) {
          conv.my_last_read_seq = myLastReadSeq;
        }
        await database.runAsync(
          `UPDATE conversation_list_cache SET data = ? WHERE id = ?`,
          [JSON.stringify(conv), String(conversationId)]
        );
      }
    }

    // 更新 conversation_cache
    const cacheRow = await database.getFirstAsync<{ data: string }>(
      `SELECT data FROM conversation_cache WHERE id = ?`,
      [String(conversationId)]
    );
    if (cacheRow?.data) {
      const conv = safeParseJson<Record<string, unknown>>(cacheRow.data);
      if (conv) {
        conv.unread_count = count;
        if (typeof myLastReadSeq === 'number' && !Number.isNaN(myLastReadSeq)) {
          conv.my_last_read_seq = myLastReadSeq;
        }
        await database.runAsync(
          `UPDATE conversation_cache SET data = ? WHERE id = ?`,
          [JSON.stringify(conv), String(conversationId)]
        );
      }
    }
  });
};

/**
 * 批量保存会话列表及其相关数据（用户、群组）
 * 在单个队列操作中完成，避免多次并发数据库操作导致的 statement 生命周期问题
 */
export const saveConversationsWithRelatedCache = async (
  conversations: ConversationResponse[],
  users?: UserDTO[],
  groups?: GroupResponse[]
): Promise<void> => {
  if (!conversations || conversations.length === 0) return;
  
  const now = new Date().toISOString();
  
  await enqueueWrite(async () => {
    const database = await getDb();
    
    // 1. 保存会话列表
    for (const conversation of conversations) {
      await database.runAsync(
        `INSERT OR REPLACE INTO conversation_list_cache (id, data, updatedAt) VALUES (?, ?, ?)`,
        [
          String(conversation.id),
          JSON.stringify(conversation),
          conversation.updated_at || now,
        ]
      );
    }
    
    // 2. 保存用户
    if (users && users.length > 0) {
      for (const user of users) {
        await database.runAsync(
          `INSERT OR REPLACE INTO users (id, data, updatedAt) VALUES (?, ?, ?)`,
          [String(user.id), JSON.stringify(user), now]
        );
      }
    }
    
    // 3. 保存群组
    if (groups && groups.length > 0) {
      for (const group of groups) {
        await database.runAsync(
          `INSERT OR REPLACE INTO groups (id, data, updatedAt) VALUES (?, ?, ?)`,
          [String(group.id), JSON.stringify(group), now]
        );
      }
    }
  });
};
