import { app, BrowserWindow, ipcMain, shell, dialog } from 'electron';
import * as path from 'path';
import * as fs from 'fs';
import * as crypto from 'crypto';
import express from 'express';
import { GrpcClient } from './modules/grpc-client';
import { DatabaseManager } from './modules/database';
import { addressDerivationService, CHAIN_CONFIGS } from './modules/address-derivation';
import { KavaTxService, KAVA_MAINNET_TX_CONFIG, KAVA_TESTNET_TX_CONFIG } from './modules/kava-tx-service';
import { AccountClient } from './modules/account-client';
import { TSSHandler, MockTSSHandler, KeygenResult } from './modules/tss-handler';

// 内置 HTTP 服务器端口
const HTTP_PORT = 3456;

// 是否使用 Mock TSS Handler (开发模式)
// 注意：即使是开发模式，默认也使用真实的 TSS Handler
// 只有显式设置 USE_MOCK_TSS=true 才会使用 Mock Handler
const USE_MOCK_TSS = process.env.USE_MOCK_TSS === 'true';

// ===========================================================================
// 调试日志系统
// ===========================================================================
let debugLogEnabled = false;

type LogLevel = 'info' | 'warn' | 'error' | 'debug';
type LogSource = 'main' | 'grpc' | 'tss' | 'account' | 'renderer' | 'kava';

function sendDebugLog(level: LogLevel, source: LogSource, message: string) {
  if (debugLogEnabled && mainWindow) {
    mainWindow.webContents.send('debug:log', { level, source, message });
  }
  // 同时输出到控制台
  const prefix = `[${source.toUpperCase()}]`;
  switch (level) {
    case 'error':
      console.error(prefix, message);
      break;
    case 'warn':
      console.warn(prefix, message);
      break;
    case 'debug':
      console.debug(prefix, message);
      break;
    default:
      console.log(prefix, message);
  }
}

// 创建日志辅助函数
const debugLog = {
  info: (source: LogSource, message: string) => sendDebugLog('info', source, message),
  warn: (source: LogSource, message: string) => sendDebugLog('warn', source, message),
  error: (source: LogSource, message: string) => sendDebugLog('error', source, message),
  debug: (source: LogSource, message: string) => sendDebugLog('debug', source, message),
};

let mainWindow: BrowserWindow | null = null;
let grpcClient: GrpcClient | null = null;
let database: DatabaseManager | null = null;
let httpServer: ReturnType<typeof express.application.listen> | null = null;
let kavaTxService: KavaTxService | null = null;
let accountClient: AccountClient | null = null;
let tssHandler: TSSHandler | MockTSSHandler | null = null;

// 当前正在进行的 Keygen 会话信息
interface ActiveKeygenSession {
  sessionId: string;
  partyIndex: number;
  participants: Array<{ partyId: string; partyIndex: number; name: string }>;
  threshold: { t: number; n: number };
  walletName: string;
  encryptionPassword: string;
}
let activeKeygenSession: ActiveKeygenSession | null = null;

// Keygen 幂等性保护：追踪正在进行的 keygen 会话 ID
let keygenInProgressSessionId: string | null = null;

// ===========================================================================
// Co-Sign 相关状态
// ===========================================================================

// 当前正在进行的 Co-Sign 会话信息
interface ActiveCoSignSession {
  sessionId: string;
  partyIndex: number;
  participants: Array<{ partyId: string; partyIndex: number; name: string }>;
  threshold: { t: number; n: number };
  walletName: string;
  messageHash: string;
  shareId: string;
  sharePassword: string;
}
let activeCoSignSession: ActiveCoSignSession | null = null;

// Co-Sign 幂等性保护：追踪正在进行的签名会话 ID
let signInProgressSessionId: string | null = null;

// 会话事件缓存 - 解决前端订阅时可能错过事件的时序问题
// 当事件到达时，前端可能还在页面导航中，尚未订阅
interface SessionEventData {
  type: string;
  sessionId: string;
  thresholdN?: number;
  thresholdT?: number;
  selectedParties?: string[];
  publicKey?: string;
  shareId?: string;
  allCompleted?: boolean;
  error?: string;
}
const sessionEventCache = new Map<string, SessionEventData[]>();
const SESSION_EVENT_CACHE_MAX_AGE = 60000; // 60秒后清理缓存
const sessionEventCacheTimestamps = new Map<string, number>();

// 添加事件到缓存
function cacheSessionEvent(sessionId: string, event: SessionEventData) {
  if (!sessionEventCache.has(sessionId)) {
    sessionEventCache.set(sessionId, []);
  }
  sessionEventCache.get(sessionId)!.push(event);
  sessionEventCacheTimestamps.set(sessionId, Date.now());

  // 清理过期缓存
  cleanExpiredEventCache();
}

// 获取并清除缓存的事件
function getAndClearCachedEvents(sessionId: string): SessionEventData[] {
  const events = sessionEventCache.get(sessionId) || [];
  sessionEventCache.delete(sessionId);
  sessionEventCacheTimestamps.delete(sessionId);
  return events;
}

// 清理过期缓存
function cleanExpiredEventCache() {
  const now = Date.now();
  for (const [sessionId, timestamp] of sessionEventCacheTimestamps.entries()) {
    if (now - timestamp > SESSION_EVENT_CACHE_MAX_AGE) {
      sessionEventCache.delete(sessionId);
      sessionEventCacheTimestamps.delete(sessionId);
    }
  }
}

// 检查并触发 keygen（在收到 all_joined 事件后调用）
// 5 分钟超时是指：所有人加入后，启动 keygen 的超时时间
// 注意：此函数应该在收到 all_joined 事件后才调用，而不是 joinSession 后立即调用
async function checkAndTriggerKeygen(sessionId: string) {
  console.log('[KEYGEN] checkAndTriggerKeygen called with sessionId:', sessionId);

  if (!activeKeygenSession || activeKeygenSession.sessionId !== sessionId) {
    console.log('[KEYGEN] No matching active keygen session for', sessionId);
    return;
  }

  console.log('[KEYGEN] Active session found:', {
    sessionId: activeKeygenSession.sessionId,
    partyIndex: activeKeygenSession.partyIndex,
    threshold: activeKeygenSession.threshold,
    participantCount: activeKeygenSession.participants.length,
  });

  // 如果 TSS 已经在运行，不重复触发
  if (tssHandler?.getIsRunning()) {
    console.log('[KEYGEN] TSS already running, skip check');
    return;
  }

  const pollIntervalMs = 2000; // 2秒轮询间隔
  const maxWaitMs = 5 * 60 * 1000; // 5分钟超时（所有人加入后的启动超时）
  const startTime = Date.now();

  console.log('[KEYGEN] Starting to poll session status...');
  debugLog.info('main', `Starting to poll session status for ${sessionId}`);

  while (Date.now() - startTime < maxWaitMs) {
    // 检查会话是否仍然有效
    if (!activeKeygenSession || activeKeygenSession.sessionId !== sessionId) {
      debugLog.warn('main', 'Active keygen session changed, stopping poll');
      return;
    }

    // 如果 TSS 已经在运行（可能被其他事件触发），停止轮询
    if (tssHandler?.getIsRunning()) {
      debugLog.info('main', 'TSS started running, stopping poll');
      return;
    }

    try {
      const status = await accountClient?.getSessionStatus(sessionId);
      if (!status) {
        debugLog.warn('main', 'Failed to get session status, will retry');
        await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
        continue;
      }

      // 优先使用后端返回的 threshold 值
      const thresholdN = status.threshold_n || status.total_parties || activeKeygenSession.threshold.n;
      const thresholdT = status.threshold_t || activeKeygenSession.threshold.t;
      const expectedN = thresholdN;
      const currentParticipants = status.participants?.length || 0;

      debugLog.debug('main', `Session ${sessionId} status: ${status.status}, participants: ${currentParticipants}/${expectedN}, threshold: ${thresholdT}-of-${thresholdN}`);

      // 检查是否满足启动条件
      const hasAllParticipants = currentParticipants >= expectedN;
      const statusReady = status.status === 'in_progress' ||
                          status.status === 'all_joined' ||
                          status.status === 'waiting_for_keygen';

      console.log('[KEYGEN] Check conditions:', {
        hasAllParticipants,
        statusReady,
        currentParticipants,
        expectedN,
        status: status.status,
      });

      if (hasAllParticipants && statusReady) {
        console.log('[KEYGEN] Conditions met! Triggering keygen...');
        debugLog.info('main', `All ${expectedN} participants joined (status: ${status.status}), triggering keygen...`);

        // 使用后端返回的 participants 信息（包含正确的 party_index）
        if (status.participants && status.participants.length > 0) {
          const myPartyId = grpcClient?.getPartyId();
          const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];

          for (const p of status.participants) {
            const existing = activeKeygenSession.participants.find(ep => ep.partyId === p.party_id);
            updatedParticipants.push({
              partyId: p.party_id,
              partyIndex: p.party_index,
              name: existing?.name || (p.party_id === myPartyId ? '我' : `参与方 ${p.party_index + 1}`),
            });
          }

          activeKeygenSession.participants = updatedParticipants;

          const myInfo = updatedParticipants.find(p => p.partyId === myPartyId);
          if (myInfo) {
            activeKeygenSession.partyIndex = myInfo.partyIndex;
          }

          debugLog.info('main', `Updated participants from server: ${JSON.stringify(updatedParticipants.map(p => ({
            partyId: p.partyId.substring(0, 8) + '...',
            partyIndex: p.partyIndex,
          })))}`);
        }

        // 更新 activeKeygenSession 的 threshold（使用后端返回的正确值）
        activeKeygenSession.threshold = { t: thresholdT, n: thresholdN };

        const selectedParties = activeKeygenSession.participants.map(p => p.partyId);

        await handleSessionStart({
          eventType: 'session_started',
          sessionId: sessionId,
          thresholdN: thresholdN,
          thresholdT: thresholdT,
          selectedParties: selectedParties,
        });

        return; // 成功触发，退出循环
      }

      // 等待下次轮询
      await new Promise(resolve => setTimeout(resolve, pollIntervalMs));

    } catch (error) {
      debugLog.error('main', `Failed to check session status: ${error}, will retry`);
      await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
    }
  }

  // 超时 - 所有人已加入但 5 分钟内未能启动 keygen
  debugLog.error('main', `Timeout: failed to start keygen within 5 minutes after all_joined for session ${sessionId}`);

  // 通知前端超时
  if (mainWindow) {
    mainWindow.webContents.send(`session:events:${sessionId}`, {
      type: 'keygen_start_timeout',
      error: '启动密钥生成超时，请重试',
    });
  }
}

// 创建主窗口
function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    minWidth: 800,
    minHeight: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
    },
    titleBarStyle: 'hiddenInset',
    show: false,
  });

  // 开发模式下加载 Vite 开发服务器
  if (process.env.NODE_ENV === 'development') {
    mainWindow.loadURL('http://localhost:5173');
    mainWindow.webContents.openDevTools();
  } else {
    // 生产模式下加载打包后的文件
    mainWindow.loadFile(path.join(__dirname, '../dist/index.html'));
  }

  mainWindow.once('ready-to-show', () => {
    mainWindow?.show();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  // 处理外部链接
  mainWindow.webContents.setWindowOpenHandler(({ url }) => {
    shell.openExternal(url);
    return { action: 'deny' };
  });
}

// 启动内置 HTTP 服务器
function startHttpServer() {
  const expressApp = express();

  expressApp.use(express.json());
  expressApp.use(express.static(path.join(__dirname, '../dist')));

  // API 路由
  expressApp.get('/api/status', (_req, res) => {
    res.json({
      connected: grpcClient?.isConnected() ?? false,
      partyId: grpcClient?.getPartyId() ?? null,
    });
  });

  // 所有其他路由返回 index.html (SPA)
  expressApp.get('*', (_req, res) => {
    res.sendFile(path.join(__dirname, '../dist/index.html'));
  });

  httpServer = expressApp.listen(HTTP_PORT, '127.0.0.1', () => {
    console.log(`HTTP server running at http://127.0.0.1:${HTTP_PORT}`);
  });
}

// 生成或获取持久化的 partyId
function getOrCreatePartyId(db: DatabaseManager): string {
  const settings = db.getAllSettings();
  let partyId = settings['party_id'];
  if (!partyId) {
    // 生成一个新的 UUID 作为 partyId
    partyId = crypto.randomUUID();
    db.setSetting('party_id', partyId);
    debugLog.info('main', `Generated new partyId: ${partyId}`);
  } else {
    debugLog.info('main', `Loaded existing partyId: ${partyId}`);
  }
  return partyId;
}

// 初始化服务
async function initServices() {
  // 初始化数据库 (必须首先初始化)
  database = new DatabaseManager();
  // 等待数据库初始化完成（加载 WASM 和创建表）
  await database.waitForReady();
  debugLog.info('main', 'Database initialized');

  // 初始化 gRPC 客户端
  grpcClient = new GrpcClient();

  // 清理过期的已处理消息记录（防止数据库膨胀）
  database.cleanupOldProcessedMessages();
  debugLog.debug('main', 'Cleaned up old processed messages');

  // 初始化 TSS Handler
  if (USE_MOCK_TSS) {
    debugLog.info('tss', 'Using Mock TSS Handler (development mode)');
    tssHandler = new MockTSSHandler(grpcClient);
  } else {
    debugLog.info('tss', 'Using real TSS Handler');
    tssHandler = new TSSHandler(grpcClient, database);
  }

  // 设置 TSS 进度事件监听
  tssHandler.on('progress', (progress: { round: number; totalRounds: number }) => {
    debugLog.info('tss', `Keygen progress: round ${progress.round}/${progress.totalRounds}`);
    // 通知前端更新进度
    if (activeKeygenSession) {
      mainWindow?.webContents.send(`session:events:${activeKeygenSession.sessionId}`, {
        type: 'progress',
        round: progress.round,
        totalRounds: progress.totalRounds,
      });
    }
  });

  tssHandler.on('error', (error: Error) => {
    debugLog.error('tss', `TSS error: ${error.message}`);
    if (activeKeygenSession) {
      mainWindow?.webContents.send(`session:events:${activeKeygenSession.sessionId}`, {
        type: 'failed',
        error: error.message,
      });
    }
  });

  // 初始化 Kava 交易服务 (从数据库读取网络设置，默认主网)
  const kavaNetwork = database.getSetting('kava_network') || 'mainnet';
  const kavaConfig = kavaNetwork === 'mainnet' ? KAVA_MAINNET_TX_CONFIG : KAVA_TESTNET_TX_CONFIG;
  kavaTxService = new KavaTxService(kavaConfig);
  debugLog.info('kava', `Kava network: ${kavaNetwork}`);

  // 初始化 Account 服务 HTTP 客户端
  // 从数据库读取 Account 服务 URL，默认使用生产环境地址
  const settings = database.getAllSettings();
  const accountServiceUrl = settings['account_service_url'] || 'https://rwaapi.szaiai.com';
  accountClient = new AccountClient(accountServiceUrl);
  debugLog.info('account', `Account service URL: ${accountServiceUrl}`);

  // 设置 IPC 处理器
  setupIpcHandlers();

  // 启动时自动连接并注册到 Message Router (非阻塞)
  connectAndRegisterToMessageRouter().catch((err) => {
    debugLog.error('grpc', `Background connection failed: ${err.message}`);
  });
}

// 处理会话开始事件 - 触发 Keygen
async function handleSessionStart(event: {
  eventType: string;
  sessionId: string;
  thresholdN: number;
  thresholdT: number;
  selectedParties: string[];
}) {
  console.log('[KEYGEN] handleSessionStart called:', {
    eventType: event.eventType,
    sessionId: event.sessionId,
    thresholdN: event.thresholdN,
    thresholdT: event.thresholdT,
    selectedParties: event.selectedParties?.length,
  });

  if (!activeKeygenSession) {
    console.log('[KEYGEN] No active keygen session, ignoring');
    debugLog.debug('main', 'No active keygen session, ignoring session start event');
    return;
  }

  if (activeKeygenSession.sessionId !== event.sessionId) {
    debugLog.debug('main', `Session ID mismatch: expected ${activeKeygenSession.sessionId}, got ${event.sessionId}`);
    return;
  }

  // 幂等性保护：检查是否已经在执行 keygen
  if (keygenInProgressSessionId === event.sessionId) {
    debugLog.debug('main', `Keygen already in progress for session ${event.sessionId}, skipping duplicate trigger`);
    return;
  }

  // 再次检查 TSS 是否在运行（双重保护）
  if (tssHandler?.getIsRunning()) {
    debugLog.debug('main', 'TSS already running, skipping');
    return;
  }

  if (!tssHandler) {
    debugLog.error('tss', 'TSS handler not initialized');
    mainWindow?.webContents.send(`session:events:${event.sessionId}`, {
      type: 'failed',
      error: 'TSS handler not initialized',
    });
    return;
  }

  // 标记 keygen 开始
  keygenInProgressSessionId = event.sessionId;

  // 从事件中更新参与者列表（如果事件包含完整列表）
  // 注意：activeKeygenSession.participants 可能已经包含正确的 partyIndex（从 checkAndTriggerKeygen 更新）
  // 只有当事件来自 session_started 事件时才需要重新构建
  if (event.selectedParties && event.selectedParties.length > 0) {
    const myPartyId = grpcClient?.getPartyId();
    const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];

    event.selectedParties.forEach((partyId) => {
      // 查找已有的参与者信息（优先使用已有的 partyIndex）
      const existing = activeKeygenSession!.participants.find(p => p.partyId === partyId);
      if (existing) {
        // 保留已有的 partyIndex
        updatedParticipants.push({
          partyId: partyId,
          partyIndex: existing.partyIndex,
          name: existing.name || (partyId === myPartyId ? '我' : `参与方 ${existing.partyIndex + 1}`),
        });
      } else {
        // 找不到已有信息，这不应该发生
        debugLog.warn('main', `Party ${partyId} not found in existing participants, using fallback index`);
        updatedParticipants.push({
          partyId: partyId,
          partyIndex: updatedParticipants.length,
          name: partyId === myPartyId ? '我' : `参与方 ${updatedParticipants.length + 1}`,
        });
      }
    });

    // 按 partyIndex 排序
    updatedParticipants.sort((a, b) => a.partyIndex - b.partyIndex);
    activeKeygenSession.participants = updatedParticipants;

    // 更新自己的 partyIndex
    const myInfo = updatedParticipants.find(p => p.partyId === myPartyId);
    if (myInfo) {
      activeKeygenSession.partyIndex = myInfo.partyIndex;
    }

    debugLog.info('main', `Updated participants: ${JSON.stringify(updatedParticipants.map(p => ({
      partyId: p.partyId.substring(0, 8) + '...',
      partyIndex: p.partyIndex,
      name: p.name,
    })))}`);
  }

  console.log('[KEYGEN] Calling tssHandler.participateKeygen with:', {
    sessionId: activeKeygenSession.sessionId,
    partyId: grpcClient?.getPartyId(),
    partyIndex: activeKeygenSession.partyIndex,
    participants: activeKeygenSession.participants.map(p => ({ partyId: p.partyId.substring(0, 8), partyIndex: p.partyIndex })),
    threshold: activeKeygenSession.threshold,
  });
  debugLog.info('tss', `Starting keygen for session ${event.sessionId}...`);

  try {
    const result = await tssHandler.participateKeygen(
      activeKeygenSession.sessionId,
      grpcClient?.getPartyId() || '',
      activeKeygenSession.partyIndex,
      activeKeygenSession.participants,
      activeKeygenSession.threshold,
      activeKeygenSession.encryptionPassword
    );

    if (result.success) {
      debugLog.info('tss', 'Keygen completed successfully');
      await handleKeygenComplete(result);
    } else {
      debugLog.error('tss', `Keygen failed: ${result.error}`);
      mainWindow?.webContents.send(`session:events:${activeKeygenSession.sessionId}`, {
        type: 'failed',
        error: result.error || 'Keygen failed',
      });
      // 清除幂等性标志
      keygenInProgressSessionId = null;
    }
  } catch (error) {
    debugLog.error('tss', `Keygen error: ${(error as Error).message}`);
    mainWindow?.webContents.send(`session:events:${activeKeygenSession?.sessionId}`, {
      type: 'failed',
      error: (error as Error).message,
    });
    // 清除幂等性标志
    keygenInProgressSessionId = null;
  }
}

// 处理 Keygen 完成 - 保存 share 并报告完成
async function handleKeygenComplete(result: KeygenResult) {
  if (!activeKeygenSession || !database || !grpcClient) {
    debugLog.error('main', 'Missing required components for keygen completion');
    return;
  }

  const sessionId = activeKeygenSession.sessionId;
  const partyId = grpcClient.getPartyId();

  try {
    // 1. 保存 share 到本地数据库
    const publicKeyHex = result.publicKey.toString('hex');
    // 转换 participants 格式：从 { partyId, partyIndex, name } 到 { partyId, name }
    const participantsForSave = activeKeygenSession.participants.map(p => ({
      partyId: p.partyId,
      name: p.name,
    }));
    const saved = database.saveShare({
      sessionId: sessionId,
      walletName: activeKeygenSession.walletName,
      partyId: partyId || '',
      partyIndex: result.partyIndex,
      thresholdT: activeKeygenSession.threshold.t,
      thresholdN: activeKeygenSession.threshold.n,
      publicKeyHex: publicKeyHex,
      rawShare: result.encryptedShare.toString('base64'),
      participants: participantsForSave,
    }, activeKeygenSession.encryptionPassword);

    debugLog.info('main', `Share saved to local database: ${saved?.id}`);

    // 2. 报告完成给 session-coordinator
    const allCompleted = await grpcClient.reportCompletion(
      sessionId,
      partyId || '',
      result.publicKey
    );

    debugLog.info('grpc', `Reported completion to session-coordinator, all_completed: ${allCompleted}`);

    // 3. 通知前端
    mainWindow?.webContents.send(`session:events:${sessionId}`, {
      type: 'completed',
      publicKey: publicKeyHex,
      shareId: saved?.id,
      allCompleted: allCompleted,
    });

    // 4. 清理活跃会话和幂等性标志
    activeKeygenSession = null;
    keygenInProgressSessionId = null;
    debugLog.info('main', 'Keygen session completed and cleaned up');

  } catch (error) {
    debugLog.error('main', `Failed to handle keygen completion: ${error}`);
    mainWindow?.webContents.send(`session:events:${sessionId}`, {
      type: 'failed',
      error: (error as Error).message,
    });
    // 清除幂等性标志
    keygenInProgressSessionId = null;
  }
}

// ===========================================================================
// Co-Sign 相关处理函数
// ===========================================================================

// 检查并触发 Co-Sign（在收到 all_joined 事件后调用）
async function checkAndTriggerCoSign(sessionId: string) {
  console.log('[CO-SIGN] checkAndTriggerCoSign called with sessionId:', sessionId);

  if (!activeCoSignSession || activeCoSignSession.sessionId !== sessionId) {
    console.log('[CO-SIGN] No matching active co-sign session for', sessionId);
    return;
  }

  console.log('[CO-SIGN] Active session found:', {
    sessionId: activeCoSignSession.sessionId,
    partyIndex: activeCoSignSession.partyIndex,
    threshold: activeCoSignSession.threshold,
    participantCount: activeCoSignSession.participants.length,
  });

  // 如果 TSS 已经在运行，不重复触发
  if (tssHandler?.getIsRunning()) {
    console.log('[CO-SIGN] TSS already running, skip check');
    return;
  }

  const pollIntervalMs = 2000; // 2秒轮询间隔
  const maxWaitMs = 5 * 60 * 1000; // 5分钟超时
  const startTime = Date.now();

  console.log('[CO-SIGN] Starting to poll session status...');
  debugLog.info('main', `Starting to poll co-sign session status for ${sessionId}`);

  while (Date.now() - startTime < maxWaitMs) {
    // 检查会话是否仍然有效
    if (!activeCoSignSession || activeCoSignSession.sessionId !== sessionId) {
      debugLog.warn('main', 'Active co-sign session changed, stopping poll');
      return;
    }

    // 如果 TSS 已经在运行，停止轮询
    if (tssHandler?.getIsRunning()) {
      debugLog.info('main', 'TSS started running, stopping poll');
      return;
    }

    try {
      // 获取签名会话状态
      const status = await accountClient?.getSignSessionStatus(sessionId);
      if (!status) {
        debugLog.warn('main', 'Failed to get sign session status, will retry');
        await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
        continue;
      }

      const expectedT = activeCoSignSession.threshold.t;
      const currentParticipants = status.joined_count || 0;

      debugLog.debug('main', `Sign session ${sessionId} status: ${status.status}, participants: ${currentParticipants}/${expectedT}`);

      // 检查是否满足启动条件
      const hasAllParticipants = currentParticipants >= expectedT;
      const statusReady = status.status === 'in_progress' ||
                          status.status === 'all_joined' ||
                          status.status === 'waiting_for_sign';

      console.log('[CO-SIGN] Check conditions:', {
        hasAllParticipants,
        statusReady,
        currentParticipants,
        expectedT,
        status: status.status,
      });

      if (hasAllParticipants && statusReady) {
        console.log('[CO-SIGN] Conditions met! Triggering sign...');
        debugLog.info('main', `All ${expectedT} participants joined (status: ${status.status}), triggering sign...`);

        // 更新参与者列表
        if (status.parties && status.parties.length > 0) {
          const myPartyId = grpcClient?.getPartyId();
          const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];

          for (const p of status.parties) {
            const existing = activeCoSignSession.participants.find(ep => ep.partyId === p.party_id);
            updatedParticipants.push({
              partyId: p.party_id,
              partyIndex: p.party_index,
              name: existing?.name || (p.party_id === myPartyId ? '我' : `参与方 ${p.party_index + 1}`),
            });
          }

          activeCoSignSession.participants = updatedParticipants;

          const myInfo = updatedParticipants.find(p => p.partyId === myPartyId);
          if (myInfo) {
            activeCoSignSession.partyIndex = myInfo.partyIndex;
          }
        }

        const selectedParties = activeCoSignSession.participants.map(p => p.partyId);

        await handleCoSignStart({
          eventType: 'session_started',
          sessionId: sessionId,
          thresholdT: activeCoSignSession.threshold.t,
          thresholdN: activeCoSignSession.threshold.n,
          selectedParties: selectedParties,
        });

        return;
      }

      await new Promise(resolve => setTimeout(resolve, pollIntervalMs));

    } catch (error) {
      debugLog.error('main', `Failed to check sign session status: ${error}, will retry`);
      await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
    }
  }

  // 超时
  debugLog.error('main', `Timeout: failed to start sign within 5 minutes for session ${sessionId}`);

  if (mainWindow) {
    mainWindow.webContents.send(`cosign:events:${sessionId}`, {
      type: 'sign_start_timeout',
      error: '启动签名超时，请重试',
    });
  }
}

// 处理 Co-Sign 会话开始事件 - 触发签名
async function handleCoSignStart(event: {
  eventType: string;
  sessionId: string;
  thresholdT: number;
  thresholdN: number;
  selectedParties: string[];
}) {
  console.log('[CO-SIGN] handleCoSignStart called:', {
    eventType: event.eventType,
    sessionId: event.sessionId,
    thresholdT: event.thresholdT,
    thresholdN: event.thresholdN,
    selectedParties: event.selectedParties?.length,
  });

  if (!activeCoSignSession) {
    console.log('[CO-SIGN] No active co-sign session, ignoring');
    debugLog.debug('main', 'No active co-sign session, ignoring sign start event');
    return;
  }

  if (activeCoSignSession.sessionId !== event.sessionId) {
    debugLog.debug('main', `Session ID mismatch: expected ${activeCoSignSession.sessionId}, got ${event.sessionId}`);
    return;
  }

  // 幂等性保护
  if (signInProgressSessionId === event.sessionId) {
    debugLog.debug('main', `Sign already in progress for session ${event.sessionId}, skipping duplicate trigger`);
    return;
  }

  if (tssHandler?.getIsRunning()) {
    debugLog.debug('main', 'TSS already running, skipping');
    return;
  }

  if (!tssHandler || !('participateSign' in tssHandler)) {
    debugLog.error('tss', 'TSS handler not initialized or does not support signing');
    mainWindow?.webContents.send(`cosign:events:${event.sessionId}`, {
      type: 'failed',
      error: 'TSS handler not initialized',
    });
    return;
  }

  // 标记签名开始
  signInProgressSessionId = event.sessionId;

  // CRITICAL: Get the original partyId from keygen (stored in share) for signing
  // This is essential for backup/restore - the partyId must match what was used during keygen
  const share = database?.getShare(activeCoSignSession.shareId, activeCoSignSession.sharePassword);
  if (!share) {
    debugLog.error('main', 'Failed to get share data');
    mainWindow?.webContents.send(`cosign:events:${event.sessionId}`, {
      type: 'failed',
      error: 'Failed to get share data',
    });
    signInProgressSessionId = null;
    return;
  }
  const signingPartyId = share.party_id || grpcClient?.getPartyId() || '';
  debugLog.info('main', `Using signingPartyId=${signingPartyId} (currentDevicePartyId=${grpcClient?.getPartyId()})`);

  // 打印当前 activeCoSignSession.participants 状态
  console.log('[CO-SIGN] Current activeCoSignSession.participants before update:',
    activeCoSignSession.participants.map(p => ({
      partyId: p.partyId.substring(0, 8),
      partyIndex: p.partyIndex,
    }))
  );
  console.log('[CO-SIGN] event.selectedParties:', event.selectedParties?.map(id => id.substring(0, 8)));

  // 从 event.selectedParties 更新参与者列表
  // 优先使用 activeCoSignSession.participants 中的 partyIndex（来自 signingParties 或 other_parties）
  // CRITICAL: Use signingPartyId (original from keygen) for identification
  if (event.selectedParties && event.selectedParties.length > 0) {
    const myPartyId = signingPartyId;
    const updatedParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = [];

    event.selectedParties.forEach((partyId) => {
      // 查找已有的参与者信息
      const existingParticipant = activeCoSignSession?.participants.find(p => p.partyId === partyId);
      if (existingParticipant) {
        // 使用已有的 partyIndex
        updatedParticipants.push({
          partyId: partyId,
          partyIndex: existingParticipant.partyIndex,
          name: partyId === myPartyId ? '我' : existingParticipant.name,
        });
      } else {
        // 找不到已有信息，这不应该发生 - 记录警告
        console.warn(`[CO-SIGN] WARNING: Party ${partyId.substring(0, 8)} not found in activeCoSignSession.participants!`);
        // 不使用 fallback index，直接跳过，这会导致参与者数量不足，签名会失败
        // 这样可以更早发现问题
      }
    });

    // 检查参与者数量是否符合预期
    if (updatedParticipants.length !== event.selectedParties.length) {
      console.error(`[CO-SIGN] ERROR: Participant count mismatch! Expected ${event.selectedParties.length}, got ${updatedParticipants.length}`);
    }

    // 按 partyIndex 排序
    updatedParticipants.sort((a, b) => a.partyIndex - b.partyIndex);

    activeCoSignSession.participants = updatedParticipants;
    console.log('[CO-SIGN] Updated participants from session_started event:', updatedParticipants.map(p => ({
      partyId: p.partyId.substring(0, 8),
      partyIndex: p.partyIndex,
    })));
  }

  // Note: share already fetched above for getting signingPartyId

  console.log('[CO-SIGN] Calling tssHandler.participateSign with:', {
    sessionId: activeCoSignSession.sessionId,
    partyId: signingPartyId,  // CRITICAL: Use signingPartyId (original from keygen)
    partyIndex: activeCoSignSession.partyIndex,
    participants: activeCoSignSession.participants.map(p => ({ partyId: p.partyId.substring(0, 8), partyIndex: p.partyIndex })),
    threshold: activeCoSignSession.threshold,
    messageHash: activeCoSignSession.messageHash.substring(0, 16) + '...',
  });
  debugLog.info('tss', `Starting sign for session ${event.sessionId}...`);

  try {
    // CRITICAL: Use signingPartyId (original partyId from keygen) for signing
    const result = await (tssHandler as TSSHandler).participateSign(
      activeCoSignSession.sessionId,
      signingPartyId,  // CRITICAL: Use original partyId from keygen for backup/restore to work
      activeCoSignSession.partyIndex,
      activeCoSignSession.participants,
      activeCoSignSession.threshold,
      activeCoSignSession.messageHash,
      share.raw_share,
      activeCoSignSession.sharePassword
    );

    if (result.success) {
      debugLog.info('tss', 'Sign completed successfully');
      await handleCoSignComplete(result);
    } else {
      debugLog.error('tss', `Sign failed: ${result.error}`);
      mainWindow?.webContents.send(`cosign:events:${activeCoSignSession.sessionId}`, {
        type: 'failed',
        error: result.error || 'Sign failed',
      });
      signInProgressSessionId = null;
    }
  } catch (error) {
    debugLog.error('tss', `Sign error: ${(error as Error).message}`);
    mainWindow?.webContents.send(`cosign:events:${activeCoSignSession?.sessionId}`, {
      type: 'failed',
      error: (error as Error).message,
    });
    signInProgressSessionId = null;
  }
}

// 处理 Co-Sign 完成 - 保存签名并报告完成
async function handleCoSignComplete(result: { success: boolean; signature: Buffer; error?: string }) {
  if (!activeCoSignSession || !database || !grpcClient) {
    debugLog.error('main', 'Missing required components for sign completion');
    return;
  }

  const sessionId = activeCoSignSession.sessionId;
  const partyId = grpcClient.getPartyId();

  try {
    const signatureHex = result.signature.toString('hex');

    // 1. 更新签名历史
    database.updateSigningHistory(sessionId, {
      status: 'completed',
      signature: signatureHex,
    });

    debugLog.info('main', `Signature saved: ${signatureHex.substring(0, 32)}...`);

    // 2. 报告完成给 session-coordinator
    const allCompleted = await grpcClient.reportCompletion(
      sessionId,
      partyId || '',
      result.signature
    );

    debugLog.info('grpc', `Reported sign completion to session-coordinator, all_completed: ${allCompleted}`);

    // 3. 通知前端
    mainWindow?.webContents.send(`cosign:events:${sessionId}`, {
      type: 'completed',
      signature: signatureHex,
      allCompleted: allCompleted,
    });

    // 4. 清理活跃会话和幂等性标志
    activeCoSignSession = null;
    signInProgressSessionId = null;
    debugLog.info('main', 'Co-Sign session completed and cleaned up');

  } catch (error) {
    debugLog.error('main', `Failed to handle sign completion: ${error}`);
    mainWindow?.webContents.send(`cosign:events:${sessionId}`, {
      type: 'failed',
      error: (error as Error).message,
    });
    signInProgressSessionId = null;
  }
}

// 连接并注册到 Message Router
async function connectAndRegisterToMessageRouter() {
  if (!grpcClient || !database) {
    debugLog.error('grpc', 'gRPC client or database not initialized');
    return;
  }

  try {
    const settings = database.getAllSettings();
    const routerUrl = settings['message_router_url'] || 'mpc-grpc.szaiai.com:443';
    const partyId = getOrCreatePartyId(database);
    const role = 'temporary'; // Service-Party-App 使用 temporary 角色

    debugLog.info('grpc', `Connecting to Message Router: ${routerUrl}...`);
    await grpcClient.connect(routerUrl);
    debugLog.info('grpc', 'Connected to Message Router');

    debugLog.info('grpc', `Registering as party: ${partyId} (role: ${role})...`);
    await grpcClient.registerParty(partyId, role);
    debugLog.info('grpc', 'Registered to Message Router successfully');

    // 订阅会话事件
    grpcClient.subscribeSessionEvents(partyId);
    debugLog.info('grpc', 'Subscribed to session events');

    // 监听连接状态变化
    grpcClient.on('disconnected', (reason: string) => {
      debugLog.warn('grpc', `Disconnected from Message Router: ${reason}`);
      mainWindow?.webContents.send('grpc:connectionStatus', { connected: false, reason });
    });

    grpcClient.on('reconnected', () => {
      debugLog.info('grpc', 'Reconnected to Message Router');
      mainWindow?.webContents.send('grpc:connectionStatus', { connected: true });
    });

    grpcClient.on('reconnectFailed', (reason: string) => {
      debugLog.error('grpc', `Failed to reconnect: ${reason}`);
      mainWindow?.webContents.send('grpc:connectionStatus', { connected: false, error: reason });
    });

    // 监听会话事件并处理
    // Note: gRPC response uses snake_case field names due to keepCase: true in proto-loader
    grpcClient.on('sessionEvent', async (event: {
      event_id: string;
      event_type: string;
      session_id: string;
      threshold_n: number;
      threshold_t: number;
      selected_parties: string[];
      join_tokens: Record<string, string>;
      message_hash?: Buffer;
    }) => {
      debugLog.info('grpc', `Received session event: ${event.event_type} for session ${event.session_id}`);

      const eventData: SessionEventData = {
        type: event.event_type,
        sessionId: event.session_id,
        thresholdN: event.threshold_n,
        thresholdT: event.threshold_t,
        selectedParties: event.selected_parties,
      };

      // 缓存事件（解决前端可能还未订阅的时序问题）
      cacheSessionEvent(event.session_id, eventData);

      // 转发事件到前端
      mainWindow?.webContents.send(`session:events:${event.session_id}`, eventData);

      // 根据事件类型处理 - 区分 Keygen 和 Co-Sign 会话
      const isCoSignSession = activeCoSignSession?.sessionId === event.session_id;
      const isKeygenSession = activeKeygenSession?.sessionId === event.session_id;

      if (event.event_type === 'all_joined') {
        // 收到 all_joined 事件表示所有参与方都已加入
        debugLog.info('main', `Received all_joined event for session ${event.session_id}, isCoSign=${isCoSignSession}, isKeygen=${isKeygenSession}`);

        if (isCoSignSession) {
          // Co-Sign 会话：转发到 cosign 频道并触发签名
          mainWindow?.webContents.send(`cosign:events:${event.session_id}`, eventData);
          setImmediate(() => {
            checkAndTriggerCoSign(event.session_id);
          });
        } else if (isKeygenSession) {
          // Keygen 会话：启动 5 分钟倒计时
          setImmediate(() => {
            checkAndTriggerKeygen(event.session_id);
          });
        }
      } else if (event.event_type === 'session_started') {
        // session_started 事件表示可以开始了
        if (isCoSignSession) {
          // Co-Sign 会话
          mainWindow?.webContents.send(`cosign:events:${event.session_id}`, eventData);
          await handleCoSignStart({
            eventType: event.event_type,
            sessionId: event.session_id,
            thresholdN: event.threshold_n,
            thresholdT: event.threshold_t,
            selectedParties: event.selected_parties,
          });
        } else if (isKeygenSession) {
          // Keygen 会话
          await handleSessionStart({
            eventType: event.event_type,
            sessionId: event.session_id,
            thresholdN: event.threshold_n,
            thresholdT: event.threshold_t,
            selectedParties: event.selected_parties,
          });
        }
      } else if (event.event_type === 'participant_joined') {
        // 参与者加入事件 - 也需要区分会话类型
        if (isCoSignSession) {
          mainWindow?.webContents.send(`cosign:events:${event.session_id}`, eventData);
        }
      }
    });
  } catch (error) {
    console.error('Failed to connect/register to Message Router:', (error as Error).message);
    // 不抛出错误，允许应用继续启动，用户可以稍后手动重试
  }
}

// 设置 IPC 通信处理器
function setupIpcHandlers() {
  // ===========================================================================
  // gRPC 相关
  // ===========================================================================

  // gRPC 连接
  ipcMain.handle('grpc:connect', async (_event, { url }) => {
    try {
      await grpcClient?.connect(url);
      return { success: true };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 注册为参与方
  ipcMain.handle('grpc:register', async (_event, { partyId, role }) => {
    try {
      await grpcClient?.registerParty(partyId, role);
      return { success: true };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 加入会话
  ipcMain.handle('grpc:joinSession', async (_event, { sessionId, partyId, joinToken, walletName }) => {
    try {
      debugLog.info('grpc', `Joining session: sessionId=${sessionId}, partyId=${partyId}, has_token=${!!joinToken}, token_length=${joinToken?.length || 0}`);

      const result = await grpcClient?.joinSession(sessionId, partyId, joinToken);
      if (result?.success) {
        // 设置活跃的 keygen 会话信息
        // Note: gRPC response uses snake_case field names due to keepCase: true in proto-loader
        const participants: Array<{ partyId: string; partyIndex: number; name: string }> = result.other_parties?.map((p: { party_id: string; party_index: number }, idx: number) => ({
          partyId: p.party_id,
          partyIndex: p.party_index,
          name: `参与方 ${idx + 1}`, // 暂时使用默认名称
        })) || [];

        // 添加自己到参与者列表
        participants.push({
          partyId: partyId,
          partyIndex: result.party_index,
          name: '我',
        });

        // 按 partyIndex 排序
        participants.sort((a, b) => a.partyIndex - b.partyIndex);

        activeKeygenSession = {
          sessionId: sessionId,
          partyIndex: result.party_index,
          participants: participants,
          threshold: {
            t: result.session_info?.threshold_t || 0,
            n: result.session_info?.threshold_n || 0,
          },
          walletName: walletName || result.session_info?.session_id || 'Shared Wallet',
          encryptionPassword: '', // 不使用加密密码
        };

        console.log('Active keygen session set:', {
          sessionId: activeKeygenSession.sessionId,
          partyIndex: activeKeygenSession.partyIndex,
          participantCount: activeKeygenSession.participants.length,
          threshold: activeKeygenSession.threshold,
        });

        // 关键步骤：立即预订阅消息流
        // 这确保在其他方开始发送 TSS 消息时，我们已经准备好接收和缓冲
        // 即使 keygen 进程还没启动，消息也不会丢失
        if (tssHandler && 'prepareForKeygen' in tssHandler) {
          try {
            debugLog.info('tss', `Preparing for keygen: subscribing to messages for session ${sessionId}`);
            (tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(sessionId, partyId);
          } catch (prepareErr) {
            debugLog.error('tss', `Failed to prepare for keygen: ${(prepareErr as Error).message}`);
            return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
          }
        }

        // 方案 B: 检查 JoinSession 响应中的 session 状态
        // 如果 session 已经是 in_progress，说明我们是最后一个加入的
        // 此时 session_started 事件可能已经在 JoinSession 返回前到达（并被忽略）
        // 所以我们需要直接触发 keygen，而不是等待 session_started 事件
        //
        // 注意：只检查 status === 'in_progress' 就足够了
        // 因为 session 只有在所有参与者都加入后才会变成 in_progress
        // 不需要额外检查参与者数量
        const sessionStatus = result.session_info?.status;

        debugLog.info('main', `JoinSession response: status=${sessionStatus}`);

        if (sessionStatus === 'in_progress') {
          // Session 已经开始，说明我们是最后一个加入的
          // 直接触发 keygen，不需要等待 session_started 事件
          debugLog.info('main', `Session already in_progress, triggering keygen immediately (Solution B)`);

          // 使用 setImmediate 确保 activeKeygenSession 已完全设置
          setImmediate(async () => {
            const selectedParties = activeKeygenSession?.participants.map(p => p.partyId) || [];
            await handleSessionStart({
              eventType: 'session_started',
              sessionId: sessionId,
              thresholdN: result.session_info?.threshold_n || activeKeygenSession?.threshold.n || 0,
              thresholdT: result.session_info?.threshold_t || activeKeygenSession?.threshold.t || 0,
              selectedParties: selectedParties,
            });
          });
        } else {
          // Session 还未开始，等待 session_started 事件
          debugLog.info('main', `Joined session ${sessionId}, waiting for session_started event to start keygen`);
        }
      }
      return { success: true, data: result };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // gRPC - 创建会话 (通过 Account 服务 HTTP API)
  ipcMain.handle('grpc:createSession', async (_event, params) => {
    try {
      // 获取当前 party ID
      const partyId = grpcClient?.getPartyId();
      if (!partyId) {
        return { success: false, error: '请先连接到消息路由器' };
      }

      // 动态计算 server-party 数量: persistent = n - t
      // 例如: 2-of-3 -> persistent=1, 3-of-5 -> persistent=2, 4-of-7 -> persistent=3
      // 这样平台备份方数量等于"允许丢失的份额数"，确保用户丢失密钥后仍可恢复
      const persistentCount = params.thresholdN - params.thresholdT;
      const externalCount = params.thresholdT; // 用户持有的份额数量

      const result = await accountClient?.createKeygenSession({
        wallet_name: params.walletName,
        threshold_t: params.thresholdT,
        threshold_n: params.thresholdN,
        initiator_party_id: partyId,
        initiator_name: params.initiatorName || '发起者',
        persistent_count: persistentCount,
        external_count: externalCount,
        expires_in_seconds: 86400, // 24 小时
      });

      if (!result?.session_id) {
        return { success: false, error: '创建会话失败: 未返回会话ID' };
      }

      // 发起方自动加入会话
      // 优先使用 join_tokens map，如果没有则使用 wildcard token (join_token)
      const joinToken = result.join_tokens?.[partyId] || result.join_tokens?.['*'] || result.join_token;
      if (joinToken) {
        console.log('Initiator auto-joining session...');
        const joinResult = await grpcClient?.joinSession(result.session_id, partyId, joinToken);

        if (joinResult?.success) {
          // 设置活跃的 keygen 会话信息
          // Note: gRPC response uses snake_case field names due to keepCase: true in proto-loader
          const participants: Array<{ partyId: string; partyIndex: number; name: string }> = [];

          // 添加发起方（自己）
          participants.push({
            partyId: partyId,
            partyIndex: joinResult.party_index,
            name: params.initiatorName || '发起者',
          });

          activeKeygenSession = {
            sessionId: result.session_id,
            partyIndex: joinResult.party_index,
            participants: participants,
            threshold: {
              t: params.thresholdT,
              n: params.thresholdN,
            },
            walletName: params.walletName,
            encryptionPassword: '', // 不使用加密密码
          };

          console.log('Initiator active keygen session set:', {
            sessionId: activeKeygenSession.sessionId,
            partyIndex: activeKeygenSession.partyIndex,
            participantCount: activeKeygenSession.participants.length,
            threshold: activeKeygenSession.threshold,
          });

          // 关键步骤：立即预订阅消息流
          if (tssHandler && 'prepareForKeygen' in tssHandler) {
            try {
              debugLog.info('tss', `Initiator preparing for keygen: subscribing to messages for session ${result.session_id}`);
              (tssHandler as { prepareForKeygen: (sessionId: string, partyId: string) => void }).prepareForKeygen(result.session_id, partyId);
            } catch (prepareErr) {
              debugLog.error('tss', `Failed to prepare for keygen: ${(prepareErr as Error).message}`);
              return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
            }
          }

          // 方案 B: 检查 JoinSession 响应中的 session 状态
          // 发起方通常是第一个加入的，所以 session 不太可能已经是 in_progress
          // 但为了代码一致性，这里也添加检查
          const sessionStatus = joinResult.session_info?.status;

          debugLog.info('main', `Initiator JoinSession response: status=${sessionStatus}`);

          if (sessionStatus === 'in_progress') {
            debugLog.info('main', `Session already in_progress, triggering keygen immediately (Solution B)`);

            setImmediate(async () => {
              const selectedParties = activeKeygenSession?.participants.map(p => p.partyId) || [];
              await handleSessionStart({
                eventType: 'session_started',
                sessionId: result.session_id,
                thresholdN: joinResult.session_info?.threshold_n || params.thresholdN,
                thresholdT: joinResult.session_info?.threshold_t || params.thresholdT,
                selectedParties: selectedParties,
              });
            });
          } else {
            debugLog.info('main', `Initiator joined session ${result.session_id}, waiting for session_started event to start keygen`);
          }
        } else {
          console.warn('Initiator failed to join session');
        }
      } else {
        console.warn('No join token found for initiator partyId:', partyId);
      }

      return {
        success: true,
        sessionId: result?.session_id,
        inviteCode: result?.invite_code,
        walletName: result?.wallet_name,
        expiresAt: result?.expires_at,
        joinTokens: result?.join_tokens,
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // gRPC - 验证邀请码 (通过 Account 服务 HTTP API)
  ipcMain.handle('grpc:validateInviteCode', async (_event, { code }) => {
    try {
      debugLog.info('account', `Validating invite code: ${code}`);
      const result = await accountClient?.getSessionByInviteCode(code);

      debugLog.info('account', `Got session for invite code: session_id=${result?.session_id}, has_join_token=${!!result?.join_token}, token_length=${result?.join_token?.length || 0}`);

      return {
        success: true,
        sessionInfo: {
          sessionId: result?.session_id,
          walletName: result?.wallet_name,
          threshold: {
            t: result?.threshold_t,
            n: result?.threshold_n,
          },
          status: result?.status,
          currentParticipants: result?.completed_parties || result?.joined_parties || 0,
          totalParticipants: result?.total_parties || result?.threshold_n || 0,
        },
        joinToken: result?.join_token,
      };
    } catch (error) {
      debugLog.error('account', `Failed to validate invite code: ${(error as Error).message}`);
      return { success: false, error: (error as Error).message };
    }
  });

  // gRPC - 获取会话状态 (通过 Account 服务 HTTP API)
  ipcMain.handle('grpc:getSessionStatus', async (_event, { sessionId }) => {
    try {
      const result = await accountClient?.getSessionStatus(sessionId);
      // 优先使用后端返回的 threshold，否则从 activeKeygenSession 获取
      const threshold = {
        t: result?.threshold_t || activeKeygenSession?.threshold?.t || 0,
        n: result?.threshold_n || result?.total_parties || activeKeygenSession?.threshold?.n || 0,
      };
      const participants = result?.participants?.map((p, idx) => ({
        partyId: p.party_id,
        partyIndex: p.party_index,
        name: activeKeygenSession?.participants?.find(ap => ap.partyId === p.party_id)?.name || `参与方 ${idx + 1}`,
        status: p.status,
        joinedAt: new Date().toISOString(),
      })) || [];

      return {
        success: true,
        session: {
          sessionId: result?.session_id,
          walletName: activeKeygenSession?.walletName || '',
          status: result?.status,
          completedParties: result?.completed_parties,
          totalParties: result?.total_parties,
          sessionType: result?.session_type,
          publicKey: result?.public_key,
          threshold: threshold,
          participants: participants,
          currentRound: 0,
          totalRounds: 4,
        },
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // gRPC - 测试连接
  ipcMain.handle('grpc:testConnection', async (_event, { url }) => {
    try {
      // 地址格式: host:port (例如 mpc-grpc.szaiai.com:443)
      await grpcClient?.connect(url);
      return { success: true };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // gRPC - 获取已注册的参与方列表
  ipcMain.handle('grpc:getRegisteredParties', async (_event, { roleFilter, onlyOnline }) => {
    try {
      const parties = await grpcClient?.getRegisteredParties(roleFilter, onlyOnline);
      return { success: true, parties: parties || [] };
    } catch (error) {
      return { success: false, error: (error as Error).message, parties: [] };
    }
  });

  // gRPC - 获取当前 partyId
  ipcMain.handle('grpc:getPartyId', async () => {
    try {
      const partyId = grpcClient?.getPartyId();
      return { success: true, partyId: partyId || null };
    } catch (error) {
      return { success: false, error: (error as Error).message, partyId: null };
    }
  });

  // gRPC - 检查连接状态
  ipcMain.handle('grpc:isConnected', async () => {
    try {
      const connected = grpcClient?.isConnected() || false;
      return { success: true, connected };
    } catch (error) {
      return { success: false, error: (error as Error).message, connected: false };
    }
  });

  // gRPC - 验证签名会话 (通过 Account 服务 HTTP API)
  ipcMain.handle('grpc:validateSigningSession', async (_event, { code }) => {
    try {
      const result = await accountClient?.getSignSessionByInviteCode(code);
      return {
        success: true,
        session: {
          sessionId: result?.session_id,
          keygenSessionId: result?.keygen_session_id,
          walletName: result?.wallet_name,
          messageHash: result?.message_hash,
          threshold: {
            t: result?.threshold_t,
            n: result?.threshold_n,
          },
          currentParticipants: result?.joined_count || 0,
          status: result?.status,
          parties: result?.parties,
          initiator: '发起者',
        },
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // gRPC - 加入签名会话
  ipcMain.handle('grpc:joinSigningSession', async (_event, params) => {
    try {
      // 从本地 SQLite 获取 share 数据
      const share = database?.getShare(params.shareId, params.password);
      if (!share) {
        return { success: false, error: 'Share not found or incorrect password' };
      }

      // 加入签名会话 (通过 gRPC)
      // TODO: 实际加入会话逻辑需要使用 gRPC client
      // 这里先返回成功，表示验证通过
      return {
        success: true,
        partyId: share.party_id,
        partyIndex: share.party_index,
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // ===========================================================================
  // Account 服务相关 (HTTP API)
  // ===========================================================================

  // 创建签名会话
  ipcMain.handle('account:createSignSession', async (_event, params) => {
    try {
      // 从本地 SQLite 获取 share 数据
      const share = database?.getShare(params.shareId, params.password);
      if (!share) {
        return { success: false, error: 'Share not found or incorrect password' };
      }

      // 解析 participants_json 获取参与方列表
      const participants = JSON.parse(share.participants_json || '[]');
      const parties = participants.map((p: { partyId: string }, index: number) => ({
        party_id: p.partyId,
        party_index: index,
      }));

      const result = await accountClient?.createSignSession({
        keygen_session_id: share.session_id,
        wallet_name: share.wallet_name,
        message_hash: params.messageHash,
        parties: parties,
        threshold_t: share.threshold_t,
        initiator_name: params.initiatorName,
      });

      return {
        success: true,
        sessionId: result?.session_id,
        inviteCode: result?.invite_code,
        expiresAt: result?.expires_at,
        joinToken: result?.join_token,
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取签名会话状态 (通过邀请码)
  ipcMain.handle('account:getSignSessionByInviteCode', async (_event, { inviteCode }) => {
    try {
      const result = await accountClient?.getSignSessionByInviteCode(inviteCode);
      return {
        success: true,
        session: {
          sessionId: result?.session_id,
          keygenSessionId: result?.keygen_session_id,
          walletName: result?.wallet_name,
          messageHash: result?.message_hash,
          thresholdT: result?.threshold_t,
          status: result?.status,
          inviteCode: result?.invite_code,
          expiresAt: result?.expires_at,
          parties: result?.parties,
          joinedCount: result?.joined_count,
        },
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // Account 服务健康检查
  ipcMain.handle('account:healthCheck', async () => {
    try {
      const result = await accountClient?.healthCheck();
      return { success: true, data: result };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 测试 Account 服务连接
  ipcMain.handle('account:testConnection', async () => {
    try {
      const connected = await accountClient?.testConnection();
      return { success: connected };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 更新 Account 服务 URL
  ipcMain.handle('account:updateUrl', async (_event, { url }) => {
    try {
      accountClient?.setBaseUrl(url);
      database?.setSetting('account_service_url', url);
      return { success: true };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取 Account 服务 URL
  ipcMain.handle('account:getUrl', async () => {
    return accountClient?.getBaseUrl() || 'https://rwaapi.szaiai.com';
  });

  // ===========================================================================
  // Co-Sign 相关 IPC 处理器
  // ===========================================================================

  // 创建 Co-Sign 会话
  ipcMain.handle('cosign:createSession', async (_event, params: {
    shareId: string;
    sharePassword: string;
    messageHash: string;
    initiatorName?: string;
  }) => {
    try {
      // 获取当前 party ID (用于检查连接状态)
      const currentDevicePartyId = grpcClient?.getPartyId();
      if (!currentDevicePartyId) {
        return { success: false, error: '请先连接到消息路由器' };
      }

      // 从本地获取 share 信息
      const share = database?.getShare(params.shareId, params.sharePassword);
      if (!share) {
        return { success: false, error: 'Share 不存在或密码错误' };
      }

      // CRITICAL: Use the original partyId from keygen (stored in share) for signing
      // This is essential for backup/restore - the partyId must match what was used during keygen
      const partyId = share.party_id || currentDevicePartyId;
      debugLog.info('main', `Initiator using partyId=${partyId} (currentDevicePartyId=${currentDevicePartyId})`);

      // 从后端获取 keygen 会话的参与者信息（包含正确的 party_index）
      const keygenStatus = await accountClient?.getSessionStatus(share.session_id);
      if (!keygenStatus?.participants || keygenStatus.participants.length === 0) {
        return { success: false, error: '无法获取 keygen 会话的参与者信息' };
      }

      // 过滤掉 co-managed-party-*（服务器持久方），只保留 temporary/external 用户方
      // 只有用户方持有签名私钥份额，co-managed-party 是备份/恢复用的
      const signingParties = keygenStatus.participants
        .filter(p => !p.party_id.startsWith('co-managed-party-'))
        .map(p => ({
          party_id: p.party_id,
          party_index: p.party_index,
        }));

      console.log('[CO-SIGN] Signing parties (excluding co-managed-party):', {
        total_keygen_participants: keygenStatus.participants.length,
        signing_parties_count: signingParties.length,
        signing_parties: signingParties.map(p => ({ id: p.party_id, index: p.party_index })),
      });

      if (signingParties.length < share.threshold_t) {
        return {
          success: false,
          error: `签名参与方不足: 需要 ${share.threshold_t} 个，但只有 ${signingParties.length} 个用户方`
        };
      }

      // 创建签名会话
      const result = await accountClient?.createSignSession({
        keygen_session_id: share.session_id,
        wallet_name: share.wallet_name,
        message_hash: params.messageHash,
        parties: signingParties,
        threshold_t: share.threshold_t,
        initiator_name: params.initiatorName || '发起者',
      });

      if (!result?.session_id) {
        return { success: false, error: '创建签名会话失败: 未返回会话ID' };
      }

      // 创建签名历史记录
      database?.createSigningHistory({
        shareId: params.shareId,
        sessionId: result.session_id,
        messageHash: params.messageHash,
      });

      // 发起方自动加入会话
      // 支持新格式 join_tokens (map[partyID]token) 和旧格式 join_token (单一通配符 token)
      const joinToken = result.join_tokens?.[partyId] || (result as { join_token?: string }).join_token;
      if (joinToken) {
        console.log('[CO-SIGN] Initiator auto-joining session...');
        const joinResult = await grpcClient?.joinSession(result.session_id, partyId, joinToken);

        if (joinResult?.success) {
          // 设置活跃的 Co-Sign 会话信息
          // 使用 signingParties 初始化完整的参与者列表（包含正确的 partyIndex）
          const signParticipants: Array<{ partyId: string; partyIndex: number; name: string }> = signingParties.map(p => ({
            partyId: p.party_id,
            partyIndex: p.party_index,
            name: p.party_id === partyId ? (params.initiatorName || '发起者') : `参与方 ${p.party_index + 1}`,
          }));

          console.log('[CO-SIGN] Initiator signParticipants (from signingParties):', signParticipants.map(p => ({
            partyId: p.partyId.substring(0, 8),
            partyIndex: p.partyIndex,
          })));

          activeCoSignSession = {
            sessionId: result.session_id,
            partyIndex: joinResult.party_index,
            participants: signParticipants,
            threshold: {
              t: share.threshold_t,
              n: share.threshold_n,
            },
            walletName: share.wallet_name,
            messageHash: params.messageHash,
            shareId: params.shareId,
            sharePassword: params.sharePassword,
          };

          console.log('[CO-SIGN] Initiator active session set:', {
            sessionId: activeCoSignSession.sessionId,
            partyIndex: activeCoSignSession.partyIndex,
            threshold: activeCoSignSession.threshold,
          });

          // 预订阅消息流
          if (tssHandler && 'prepareForSign' in tssHandler) {
            try {
              debugLog.info('tss', `Initiator preparing for sign: subscribing to messages for session ${result.session_id}`);
              (tssHandler as TSSHandler).prepareForSign(result.session_id, partyId);
            } catch (prepareErr) {
              debugLog.error('tss', `Failed to prepare for sign: ${(prepareErr as Error).message}`);
              return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
            }
          }

          // 检查会话状态
          const sessionStatus = joinResult.session_info?.status;
          debugLog.info('main', `Initiator JoinSession response: status=${sessionStatus}`);

          if (sessionStatus === 'in_progress') {
            debugLog.info('main', 'Session already in_progress, triggering sign immediately');
            // 从 joinResult.other_parties 获取其他参与者，加上发起者自己
            // 因为此时 activeCoSignSession.participants 只有发起者自己
            const otherParties = joinResult.other_parties || [];
            const selectedParties = [partyId, ...otherParties.map((p: { party_id: string }) => p.party_id)];
            console.log('[CO-SIGN] Initiator using other_parties + self:', selectedParties.map((id: string) => id.substring(0, 8)));

            setImmediate(async () => {
              await handleCoSignStart({
                eventType: 'session_started',
                sessionId: result.session_id,
                thresholdT: share.threshold_t,
                thresholdN: share.threshold_n,
                selectedParties: selectedParties,
              });
            });
          }
        } else {
          console.warn('[CO-SIGN] Initiator failed to join session');
        }
      }

      return {
        success: true,
        sessionId: result.session_id,
        inviteCode: result.invite_code,
        walletName: share.wallet_name,
        expiresAt: result.expires_at,
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 验证 Co-Sign 邀请码
  ipcMain.handle('cosign:validateInviteCode', async (_event, { code }) => {
    try {
      debugLog.info('account', `Validating co-sign invite code: ${code}`);
      const result = await accountClient?.getSignSessionByInviteCode(code);

      if (!result?.session_id) {
        return { success: false, error: '无效的邀请码' };
      }

      return {
        success: true,
        sessionInfo: {
          sessionId: result.session_id,
          keygenSessionId: result.keygen_session_id,
          walletName: result.wallet_name,
          messageHash: result.message_hash,
          threshold: {
            t: result.threshold_t,
            n: result.threshold_n,
          },
          status: result.status,
          currentParticipants: result.joined_count || 0,
          parties: result.parties,
        },
        joinToken: result.join_token,
      };
    } catch (error) {
      debugLog.error('account', `Failed to validate co-sign invite code: ${(error as Error).message}`);
      return { success: false, error: (error as Error).message };
    }
  });

  // 加入 Co-Sign 会话
  ipcMain.handle('cosign:joinSession', async (_event, params: {
    sessionId: string;
    shareId: string;
    sharePassword: string;
    joinToken: string;
    walletName?: string;
    messageHash: string;
    threshold: { t: number; n: number };
    parties?: Array<{ party_id: string; party_index: number }>;
  }) => {
    try {
      const currentDevicePartyId = grpcClient?.getPartyId();
      if (!currentDevicePartyId) {
        return { success: false, error: '请先连接到消息路由器' };
      }

      // 验证 share
      const share = database?.getShare(params.shareId, params.sharePassword);
      if (!share) {
        return { success: false, error: 'Share 不存在或密码错误' };
      }

      // CRITICAL: Use the original partyId from keygen (stored in share) for signing
      // This is essential for backup/restore - the partyId must match what was used during keygen
      const signingPartyId = share.party_id || currentDevicePartyId;
      debugLog.info('grpc', `Joining co-sign session: sessionId=${params.sessionId}, signingPartyId=${signingPartyId} (currentDevicePartyId=${currentDevicePartyId})`);

      const result = await grpcClient?.joinSession(params.sessionId, signingPartyId, params.joinToken);
      if (result?.success) {
        // 设置活跃的 Co-Sign 会话
        // 优先使用 params.parties（来自 validateInviteCode，包含所有预期参与者）
        // 而不是 result.other_parties（只包含已加入的参与者）
        let participants: Array<{ partyId: string; partyIndex: number; name: string }>;

        if (params.parties && params.parties.length > 0) {
          // 使用完整的 parties 列表
          // CRITICAL: Use signingPartyId (original from keygen) for identification
          participants = params.parties.map(p => ({
            partyId: p.party_id,
            partyIndex: p.party_index,
            name: p.party_id === signingPartyId ? '我' : `参与方 ${p.party_index + 1}`,
          }));
          console.log('[CO-SIGN] Participant using params.parties (complete list):', participants.map(p => ({
            partyId: p.partyId.substring(0, 8),
            partyIndex: p.partyIndex,
          })));
        } else {
          // Fallback: 使用 other_parties + 自己（可能不完整）
          console.warn('[CO-SIGN] WARNING: params.parties not available, using other_parties (may be incomplete)');
          participants = result.other_parties?.map((p: { party_id: string; party_index: number }, idx: number) => ({
            partyId: p.party_id,
            partyIndex: p.party_index,
            name: `参与方 ${idx + 1}`,
          })) || [];

          // 添加自己 - CRITICAL: Use signingPartyId (original from keygen)
          participants.push({
            partyId: signingPartyId,
            partyIndex: result.party_index,
            name: '我',
          });
        }

        // 按 partyIndex 排序
        participants.sort((a, b) => a.partyIndex - b.partyIndex);

        activeCoSignSession = {
          sessionId: params.sessionId,
          partyIndex: result.party_index,
          participants: participants,
          threshold: params.threshold,
          walletName: params.walletName || share.wallet_name,
          messageHash: params.messageHash,
          shareId: params.shareId,
          sharePassword: params.sharePassword,
        };

        console.log('[CO-SIGN] Active session set:', {
          sessionId: activeCoSignSession.sessionId,
          partyIndex: activeCoSignSession.partyIndex,
          participantCount: activeCoSignSession.participants.length,
          threshold: activeCoSignSession.threshold,
        });

        // 创建签名历史记录
        database?.createSigningHistory({
          shareId: params.shareId,
          sessionId: params.sessionId,
          messageHash: params.messageHash,
        });

        // 预订阅消息流 - CRITICAL: Use signingPartyId (original from keygen)
        if (tssHandler && 'prepareForSign' in tssHandler) {
          try {
            debugLog.info('tss', `Preparing for sign: subscribing to messages for session ${params.sessionId}, signingPartyId=${signingPartyId}`);
            (tssHandler as TSSHandler).prepareForSign(params.sessionId, signingPartyId);
          } catch (prepareErr) {
            debugLog.error('tss', `Failed to prepare for sign: ${(prepareErr as Error).message}`);
            return { success: false, error: `消息订阅失败: ${(prepareErr as Error).message}` };
          }
        }

        // 检查会话状态
        const sessionStatus = result.session_info?.status;
        debugLog.info('main', `JoinSession response: status=${sessionStatus}`);

        if (sessionStatus === 'in_progress') {
          debugLog.info('main', 'Session already in_progress, triggering sign immediately');
          // 使用 activeCoSignSession.participants（已从 other_parties + 自己构建）
          const selectedParties = activeCoSignSession?.participants.map(p => p.partyId) || [];
          console.log('[CO-SIGN] Participant using activeCoSignSession.participants:', selectedParties.map((id: string) => id.substring(0, 8)));

          setImmediate(async () => {
            await handleCoSignStart({
              eventType: 'session_started',
              sessionId: params.sessionId,
              thresholdT: params.threshold.t,
              thresholdN: params.threshold.n,
              selectedParties: selectedParties,
            });
          });
        }

        return { success: true, data: result };
      } else {
        return { success: false, error: '加入会话失败' };
      }
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取 Co-Sign 会话状态
  ipcMain.handle('cosign:getSessionStatus', async (_event, { sessionId }) => {
    try {
      const result = await accountClient?.getSignSessionStatus(sessionId);
      // API 返回的是 participants 字段
      const apiParticipants = (result as { participants?: Array<{ party_id: string; party_index: number; status: string }> })?.participants || [];
      return {
        success: true,
        session: {
          sessionId: result?.session_id,
          status: result?.status,
          joinedCount: result?.joined_count,
          inviteCode: (result as { invite_code?: string })?.invite_code || '',
          threshold: {
            t: result?.threshold_t || activeCoSignSession?.threshold?.t || 0,
            n: result?.threshold_n || activeCoSignSession?.threshold?.n || 0,
          },
          participants: apiParticipants.map((p, idx) => ({
            partyId: p.party_id,
            partyIndex: p.party_index,
            name: activeCoSignSession?.participants?.find(ap => ap.partyId === p.party_id)?.name || `参与方 ${idx + 1}`,
            status: p.status || 'waiting',
          })),
          messageHash: activeCoSignSession?.messageHash || '',
          walletName: activeCoSignSession?.walletName || '',
        },
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 订阅 Co-Sign 会话事件
  ipcMain.on('cosign:subscribeSessionEvents', (_event, { sessionId }) => {
    debugLog.debug('main', `Frontend subscribing to co-sign session events: ${sessionId}`);

    // 获取并发送缓存的事件
    const cachedEvents = getAndClearCachedEvents(sessionId);
    if (cachedEvents.length > 0) {
      debugLog.info('main', `Sending ${cachedEvents.length} cached events to frontend for co-sign session ${sessionId}`);
      for (const event of cachedEvents) {
        mainWindow?.webContents.send(`cosign:events:${sessionId}`, event);
      }
    }
  });

  // 取消订阅 Co-Sign 会话事件
  ipcMain.on('cosign:unsubscribeSessionEvents', (_event, { sessionId }) => {
    debugLog.debug('main', `Frontend unsubscribing from co-sign session events: ${sessionId}`);
  });

  // ===========================================================================
  // Share 存储相关 (SQLite)
  // ===========================================================================

  // 保存 share
  ipcMain.handle('storage:saveShare', async (_event, { share, password }) => {
    try {
      const saved = database?.saveShare({
        sessionId: share.sessionId,
        walletName: share.walletName,
        partyId: share.partyId,
        partyIndex: share.partyIndex,
        thresholdT: share.threshold.t,
        thresholdN: share.threshold.n,
        publicKeyHex: share.publicKey,
        rawShare: share.rawShare,
        participants: share.participants || [],
      }, password);

      // 自动派生 Kava 地址
      if (saved && share.publicKey) {
        try {
          const kavaAddress = addressDerivationService.deriveAddress(share.publicKey, 'kava');
          database?.saveDerivedAddress({
            shareId: saved.id,
            chain: 'kava',
            derivationPath: kavaAddress.derivationPath,
            address: kavaAddress.address,
            publicKeyHex: share.publicKey,
          });
        } catch (err) {
          console.error('Failed to derive Kava address:', err);
        }
      }

      return { success: true, data: saved };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取 share 列表
  ipcMain.handle('storage:listShares', async () => {
    try {
      const shares = database?.listShares() ?? [];
      // 转换为前端期望的格式
      const formatted = shares.map(share => ({
        id: share.id,
        sessionId: share.session_id,
        walletName: share.wallet_name,
        partyId: share.party_id,
        partyIndex: share.party_index,
        threshold: {
          t: share.threshold_t,
          n: share.threshold_n,
        },
        publicKey: share.public_key_hex,
        createdAt: share.created_at,
        lastUsedAt: share.last_used_at,
        metadata: {
          participants: JSON.parse(share.participants_json || '[]'),
        },
      }));
      return { success: true, data: formatted };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取单个 share (解密)
  ipcMain.handle('storage:getShare', async (_event, { id, password }) => {
    try {
      const share = database?.getShare(id, password);
      if (!share) return null;

      return {
        id: share.id,
        sessionId: share.session_id,
        walletName: share.wallet_name,
        partyId: share.party_id,
        partyIndex: share.party_index,
        threshold: {
          t: share.threshold_t,
          n: share.threshold_n,
        },
        publicKey: share.public_key_hex,
        rawShare: share.raw_share,
        createdAt: share.created_at,
        lastUsedAt: share.last_used_at,
        participants: JSON.parse(share.participants_json || '[]'),
      };
    } catch (error) {
      return null;
    }
  });

  // 删除 share
  ipcMain.handle('storage:deleteShare', async (_event, { id }) => {
    try {
      database?.deleteShare(id);
      return { success: true };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 导出 share
  ipcMain.handle('storage:exportShare', async (_event, { id, password }) => {
    try {
      const data = database?.exportShare(id, password);
      return { success: true, data };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 导入 share
  ipcMain.handle('storage:importShare', async (_event, { filePath, password }) => {
    try {
      const data = fs.readFileSync(filePath);
      const share = database?.importShare(data, password);
      return { success: true, share };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // ===========================================================================
  // 地址派生相关
  // ===========================================================================

  // 派生地址
  ipcMain.handle('address:derive', async (_event, { shareId, chain, password }) => {
    try {
      const share = database?.getShare(shareId, password);
      if (!share) {
        return { success: false, error: 'Share not found' };
      }

      const derived = addressDerivationService.deriveAddress(share.public_key_hex, chain);

      // 保存到数据库
      const saved = database?.saveDerivedAddress({
        shareId,
        chain,
        derivationPath: derived.derivationPath,
        address: derived.address,
        publicKeyHex: share.public_key_hex,
      });

      return { success: true, data: { ...derived, id: saved?.id } };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 派生所有支持的链地址
  ipcMain.handle('address:deriveAll', async (_event, { shareId, password }) => {
    try {
      const share = database?.getShare(shareId, password);
      if (!share) {
        return { success: false, error: 'Share not found' };
      }

      const addresses = addressDerivationService.deriveAllAddresses(share.public_key_hex);

      // 保存所有地址
      for (const addr of addresses) {
        database?.saveDerivedAddress({
          shareId,
          chain: addr.chain,
          derivationPath: addr.derivationPath,
          address: addr.address,
          publicKeyHex: share.public_key_hex,
        });
      }

      return { success: true, data: addresses };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取 share 的所有派生地址
  ipcMain.handle('address:list', async (_event, { shareId }) => {
    try {
      const addresses = database?.getAddressesByShare(shareId) ?? [];
      return {
        success: true,
        data: addresses.map(addr => ({
          id: addr.id,
          shareId: addr.share_id,
          chain: addr.chain,
          chainName: CHAIN_CONFIGS[addr.chain]?.name || addr.chain,
          derivationPath: addr.derivation_path,
          address: addr.address,
          publicKeyHex: addr.public_key_hex,
          createdAt: addr.created_at,
        })),
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取支持的链列表
  ipcMain.handle('address:getSupportedChains', async () => {
    return addressDerivationService.getSupportedChains();
  });

  // ===========================================================================
  // 签名历史相关
  // ===========================================================================

  // 获取签名历史
  ipcMain.handle('signing:getHistory', async (_event, { shareId }) => {
    try {
      const history = database?.getSigningHistoryByShare(shareId) ?? [];
      return {
        success: true,
        data: history.map(h => ({
          id: h.id,
          shareId: h.share_id,
          sessionId: h.session_id,
          messageHash: h.message_hash,
          signature: h.signature,
          status: h.status,
          errorMessage: h.error_message,
          createdAt: h.created_at,
          completedAt: h.completed_at,
        })),
      };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // ===========================================================================
  // 设置相关
  // ===========================================================================

  // 获取设置
  ipcMain.handle('storage:getSettings', async () => {
    try {
      const settings = database?.getAllSettings() ?? {};
      return {
        messageRouterUrl: settings['message_router_url'] || 'mpc-grpc.szaiai.com:443',
        autoBackup: settings['auto_backup'] === 'true',
        backupPath: settings['backup_path'] || '',
      };
    } catch (error) {
      return null;
    }
  });

  // 保存设置
  ipcMain.handle('storage:saveSettings', async (_event, { settings }) => {
    try {
      if (settings.messageRouterUrl !== undefined) {
        database?.setSetting('message_router_url', settings.messageRouterUrl);
      }
      if (settings.autoBackup !== undefined) {
        database?.setSetting('auto_backup', settings.autoBackup ? 'true' : 'false');
      }
      if (settings.backupPath !== undefined) {
        database?.setSetting('backup_path', settings.backupPath);
      }
      return { success: true };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // ===========================================================================
  // Kava 区块链相关
  // ===========================================================================

  // 查询 Kava 余额
  ipcMain.handle('kava:getBalance', async (_event, { address }) => {
    try {
      const balance = await kavaTxService?.getKavaBalance(address);
      return { success: true, data: balance };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 查询所有余额
  ipcMain.handle('kava:getAllBalances', async (_event, { address }) => {
    try {
      const balances = await kavaTxService?.getAllBalances(address);
      return { success: true, data: balances };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 查询账户信息
  ipcMain.handle('kava:getAccountInfo', async (_event, { address }) => {
    try {
      const info = await kavaTxService?.getAccountInfo(address);
      return { success: true, data: info };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 构建转账交易 (待签名)
  ipcMain.handle('kava:buildSendTx', async (_event, { fromAddress, toAddress, amount, publicKeyHex, memo }) => {
    try {
      const unsignedTx = await kavaTxService?.buildSendTx(
        fromAddress,
        toAddress,
        amount,
        publicKeyHex,
        memo || ''
      );
      return { success: true, data: unsignedTx };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 完成签名并广播交易
  ipcMain.handle('kava:completeTxAndBroadcast', async (_event, { unsignedTx, signatureHex }) => {
    try {
      // 完成交易签名
      const signedTx = await kavaTxService?.completeTx(unsignedTx, signatureHex);
      if (!signedTx) {
        return { success: false, error: 'Failed to complete transaction' };
      }

      // 广播交易
      const result = await kavaTxService?.broadcastTx(signedTx);
      return { success: true, data: result };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 查询交易状态
  ipcMain.handle('kava:getTxStatus', async (_event, { txHash }) => {
    try {
      const status = await kavaTxService?.getTxStatus(txHash);
      return { success: true, data: status };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取 Kava 配置
  ipcMain.handle('kava:getConfig', async () => {
    return kavaTxService?.getConfig();
  });

  // 更新 Kava 配置
  ipcMain.handle('kava:updateConfig', async (_event, { config }) => {
    try {
      kavaTxService?.updateConfig(config);
      return { success: true };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // Kava 健康检查
  ipcMain.handle('kava:healthCheck', async () => {
    try {
      const result = await kavaTxService?.healthCheck();
      return { success: result?.ok ?? false, data: result };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 切换 Kava 网络 (主网/测试网)
  ipcMain.handle('kava:switchNetwork', async (_event, { network }) => {
    try {
      if (network === 'testnet') {
        kavaTxService?.switchToTestnet();
        database?.setSetting('kava_network', 'testnet');
      } else {
        kavaTxService?.switchToMainnet();
        database?.setSetting('kava_network', 'mainnet');
      }
      return { success: true, network };
    } catch (error) {
      return { success: false, error: (error as Error).message };
    }
  });

  // 获取当前 Kava 网络
  ipcMain.handle('kava:getNetwork', async () => {
    const isTestnet = kavaTxService?.isTestnet() ?? false;
    return { network: isTestnet ? 'testnet' : 'mainnet' };
  });

  // ===========================================================================
  // 对话框相关
  // ===========================================================================

  // 选择目录
  ipcMain.handle('dialog:selectDirectory', async () => {
    const result = await dialog.showOpenDialog(mainWindow!, {
      properties: ['openDirectory'],
    });
    return result.canceled ? null : result.filePaths[0];
  });

  // 选择文件
  ipcMain.handle('dialog:selectFile', async (_event, { filters }) => {
    const result = await dialog.showOpenDialog(mainWindow!, {
      properties: ['openFile'],
      filters: filters || [],
    });
    return result.canceled ? null : result.filePaths[0];
  });

  // 保存文件
  ipcMain.handle('dialog:saveFile', async (_event, { defaultPath, filters }) => {
    const result = await dialog.showSaveDialog(mainWindow!, {
      defaultPath,
      filters: filters || [],
    });
    return result.canceled ? null : result.filePath;
  });

  // ===========================================================================
  // 调试相关
  // ===========================================================================

  // 订阅日志
  ipcMain.on('debug:subscribe', () => {
    debugLogEnabled = true;
    debugLog.info('main', 'Debug console connected');
  });

  // 取消订阅日志
  ipcMain.on('debug:unsubscribe', () => {
    debugLogEnabled = false;
  });

  // 接收来自渲染进程的日志
  ipcMain.on('debug:log', (_event, { level, source, message }) => {
    sendDebugLog(level as LogLevel, source as LogSource, message);
  });

  // ===========================================================================
  // 会话事件订阅（带缓存事件发送）
  // ===========================================================================

  // 前端订阅会话事件时，立即发送缓存的事件
  ipcMain.on('grpc:subscribeSessionEvents', (_event, { sessionId }) => {
    debugLog.debug('main', `Frontend subscribing to session events: ${sessionId}`);

    // 获取并发送缓存的事件
    const cachedEvents = getAndClearCachedEvents(sessionId);
    if (cachedEvents.length > 0) {
      debugLog.info('main', `Sending ${cachedEvents.length} cached events to frontend for session ${sessionId}`);
      for (const event of cachedEvents) {
        mainWindow?.webContents.send(`session:events:${sessionId}`, event);
      }
    }
  });

  // 前端取消订阅
  ipcMain.on('grpc:unsubscribeSessionEvents', (_event, { sessionId }) => {
    debugLog.debug('main', `Frontend unsubscribing from session events: ${sessionId}`);
  });
}

// 应用生命周期
app.whenReady().then(async () => {
  await initServices();
  // HTTP 服务器仅在开发模式下启动
  if (process.env.NODE_ENV === 'development') {
    startHttpServer();
  }
  createWindow();

  app.on('activate', async () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
      // macOS: 重新激活时检查并恢复 gRPC 连接
      if (grpcClient && !grpcClient.isConnected()) {
        debugLog.info('grpc', 'App activated, reconnecting to Message Router...');
        try {
          await connectAndRegisterToMessageRouter();
        } catch (err) {
          debugLog.error('grpc', `Failed to reconnect on activate: ${(err as Error).message}`);
        }
      }
    }
  });
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('before-quit', () => {
  // 清理资源
  grpcClient?.disconnect();
  database?.close();
  httpServer?.close();
  kavaTxService?.disconnect();
});
