// ============================================================
// bus — 通信层：事件总线 + IPC 守卫 + 渲染进程日志
// 合并自 event-bus.ts + ipc.ts + logger.ts
//
// 各模块职责：
//   事件总线 — 跨组件/跨模块事件通信（进程内）
//   IPC 守卫 — Electron/Browser 环境安全适配（进程间）
//   日志     — 通过 IPC 发送到主进程写文件（含事件总线审计钩子）
// ============================================================

import { RENDERER_TO_MAIN } from '@shared/constants/ipc-channels';
import { sanitizeLogEntry } from '@shared/utils/sanitize';
import type { LogEntry, LogLevel, LogCategory, LogErrorSnapshot } from '@shared/types/logging';

// ═══════════════════════════════════════════
// 一、IPC 安全守卫（原 ipc.ts）
// ═══════════════════════════════════════════

export function hasIpc(): boolean {
   return typeof window !== 'undefined' && window.ipcRenderer != null;
}

export function safeIpcOn(
   channel: string,
   listener: (event: unknown, ...args: unknown[]) => void,
): void {
   if (hasIpc()) window.ipcRenderer.on(channel, listener);
}

export function safeIpcOff(channel: string, listener: (...args: unknown[]) => void): void {
   if (hasIpc()) window.ipcRenderer.off(channel, listener);
}

export function safeIpcSend(channel: string, ...args: unknown[]): void {
   if (hasIpc()) window.ipcRenderer.send(channel, ...args);
}

export async function safeIpcInvoke(channel: string, ...args: unknown[]): Promise<unknown> {
   if (!hasIpc()) {
      console.warn(`[IPC] 非 Electron 环境，invoke "${channel}" 被忽略`);
      return undefined;
   }
   return window.ipcRenderer.invoke(channel, ...args);
}

// ═══════════════════════════════════════════
// 二、事件总线（原 event-bus.ts）
// ═══════════════════════════════════════════

type Listener = (...args: unknown[]) => void;
const listeners = new Map<string, Set<Listener>>();

type EventLogListener = (event: string, ...args: unknown[]) => void;
let eventLogListener: EventLogListener | null = null;

/** 业务错误事件的负载类型（事件总线投递用） */
export interface BusinessErrorEvent {
   /** 后端业务状态码 */
   code: number;
   /** 后端返回的错误信息（用户可读） */
   message: string;
}

/** 注册事件日志监听器（由下方 logger 模块自动调用，用于审计追踪） */
export function setEventLogListener(fn: EventLogListener): void {
   eventLogListener = fn;
}

export function on(event: string, fn: Listener): void {
   if (!listeners.has(event)) listeners.set(event, new Set());
   listeners.get(event)!.add(fn);
}

export function off(event: string, fn: Listener): void {
   listeners.get(event)?.delete(fn);
}

export function emit(event: string, ...args: unknown[]): void {
   if (eventLogListener) {
      try { eventLogListener(event, ...args); } catch { /* 日志钩子异常不影响投递 */ }
   }
   listeners.get(event)?.forEach((fn) => {
      try { fn(...args); } catch (e) { logger.warn('event', `回调出错: ${event}`, e instanceof Error ? e : undefined); }
   });
}

export const EVENTS = {
   AUTH_REQUIRED: 'auth:required',
   SHOW_LOGIN: 'auth:show-login',
   LOGIN_SUCCESS: 'auth:login-success',
   LOGOUT: 'auth:logout',
   TASK_SUBMITTED: 'task:submitted',
   BALANCE_INSUFFICIENT: 'task:balance-insufficient',
   /** 软件使用权到期（HTTP 403 + 后端 message），引导用户购买 VIP */
   SUBSCRIPTION_EXPIRED: 'auth:subscription-expired',
   OPEN_SETTINGS: 'settings:open',
   OPEN_PAGE: 'page:open',
   CLOSE_PAGE: 'page:close',
   PAGE_LOCK: 'page:lock',
} as const;

// ═══════════════════════════════════════════
// 三、渲染进程日志（原 logger.ts）
// ═══════════════════════════════════════════

function errorToSnapshot(err: Error): LogErrorSnapshot {
   return {
      name: err.name,
      message: err.message,
      stack: err.stack,
      cause: (err as { cause?: unknown }).cause
         ? String((err as { cause?: unknown }).cause)
         : undefined,
   };
}

function createEntry(
   level: LogLevel,
   category: LogCategory,
   message: string,
   error?: Error,
   context?: Record<string, unknown>,
): LogEntry {
   const entry: LogEntry = {
      timestamp: new Date().toISOString(),
      level,
      category,
      message,
      processType: 'renderer',
   };
   if (context && Object.keys(context).length > 0) entry.context = context;
   if (error) entry.error = errorToSnapshot(error);
   return entry;
}

function send(rawEntry: LogEntry): void {
   const entry = sanitizeLogEntry(rawEntry);
   if (hasIpc()) safeIpcSend(RENDERER_TO_MAIN.LOG_MESSAGE, entry);

   if (import.meta.env.DEV) {
      const prefix = `[${entry.level}][${entry.category}]`;
      const ctx = entry.context ? ` ${JSON.stringify(entry.context)}` : '';
      const errMsg = entry.error ? ` — ${entry.error.name}: ${entry.error.message}` : '';

      switch (entry.level) {
         case 'DEBUG': console.debug(prefix, entry.message, ctx); break;
         case 'INFO':  console.info(prefix, entry.message, ctx); break;
         case 'WARN':  console.warn(prefix, entry.message + errMsg, ctx); break;
         case 'ERROR': console.error(prefix, entry.message + errMsg, ctx, entry.error?.stack || ''); break;
      }
   }
}

export const logger = {
   debug(category: LogCategory, message: string, context?: Record<string, unknown>): void {
      send(createEntry('DEBUG', category, message, undefined, context));
   },
   info(category: LogCategory, message: string, context?: Record<string, unknown>): void {
      send(createEntry('INFO', category, message, undefined, context));
   },
   warn(category: LogCategory, message: string, error?: Error, context?: Record<string, unknown>): void {
      send(createEntry('WARN', category, message, error, context));
   },
   error(category: LogCategory, message: string, error?: Error, context?: Record<string, unknown>): void {
      send(createEntry('ERROR', category, message, error, context));
   },
};

// 事件总线审计钩子（模块加载时自动注册）
let eventHookRegistered = false;
export function registerEventLogHook(): void {
   if (eventHookRegistered) return;
   eventHookRegistered = true;
   setEventLogListener((event: string, ...args: unknown[]) => {
      logger.debug('event', 'Event emitted', { event, args });
   });
}
registerEventLogHook();
