/**
 * 崩溃上报（plan.md「9.5 崩溃上报」+「9.6 错误恢复 UI」）。
 *
 * 参考 AutoAccounting 的 ErrorActivity + Bugly：
 * - 全局未捕获异常捕获
 * - 崩溃日志写入文件（重启后可导出）
 * - 错误恢复 UI 数据（plan.md 9.6）
 * - 生产环境可选接入 Sentry（通过注入 SentryProvider）
 *
 * 抽象 SentryBridge 使可单测（生产环境注入 @sentry/react-native）。
 */

import { logger } from '../utils/logger';

/** Sentry 桥接抽象（生产环境注入 @sentry/react-native）。 */
export interface SentryBridge {
  init(dsn: string, environment: string): void;
  captureException(error: unknown, context?: Record<string, unknown>): void;
  captureMessage(message: string, level?: 'info' | 'warning' | 'error'): void;
}

/** 崩溃记录。 */
export interface CrashRecord {
  timestamp: string;
  message: string;
  stack?: string;
  source: 'uncaught' | 'handled' | 'sentry';
  context?: Record<string, unknown>;
}

/** 崩溃上报管理器。 */
export class CrashReporter {
  private records: CrashRecord[] = [];
  private maxRecords = 50;
  private sentry: SentryBridge | null = null;
  private installed = false;
  private fs: CrashFs | null = null;

  /** 注入文件系统后端（生产环境用 expo-file-system，测试用内存实现）。 */
  setFs(fs: CrashFs): void {
    this.fs = fs;
  }

  /** 安装全局未捕获异常捕获。 */
  install(): void {
    if (this.installed) return;
    this.installed = true;

    // Node/React Native 的全局错误捕获
    const errorHandler = (error: unknown) => {
      this.recordCrash({
        timestamp: new Date().toISOString(),
        message: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
        source: 'uncaught',
      });
    };

    // 监听未处理的 Promise rejection
    if (typeof process !== 'undefined') {
      process.on?.('unhandledRejection', errorHandler);
      process.on?.('uncaughtException', errorHandler);
    }

    // React Native ErrorUtils（RN 环境特有）
    const g = global as unknown as { ErrorUtils?: { setGlobalHandler?: (h: (e: unknown) => void) => void } };
    if (typeof global !== 'undefined' && g.ErrorUtils?.setGlobalHandler) {
      g.ErrorUtils.setGlobalHandler(errorHandler);
    }
  }

  /** 注入 Sentry（生产环境）。 */
  setSentry(sentry: SentryBridge, dsn: string, environment: string): void {
    this.sentry = sentry;
    sentry.init(dsn, environment);
  }

  /** 记录崩溃（手动或自动）。 */
  recordCrash(record: CrashRecord): void {
    this.records.push(record);
    if (this.records.length > this.maxRecords) {
      this.records.shift();
    }
    logger.error('crash', record.message, { stack: record.stack, source: record.source });

    // 持久化到文件（异步，不阻塞）
    this.persistToFs();

    // 转发到 Sentry（若已注入）
    if (this.sentry) {
      const error = record.stack ? new Error(record.message) : record.message;
      this.sentry.captureException(error, record.context);
    }
  }

  /** 持久化崩溃记录到文件。 */
  private persistToFs(): void {
    if (!this.fs) return;
    try {
      const content = JSON.stringify(this.records);
      this.fs.writeFile(content).catch(e => {
        logger.warn('crash', `持久化崩溃日志失败: ${e}`);
      });
    } catch {
      // 静默失败
    }
  }

  /** 从文件加载崩溃记录（App 启动时调用）。 */
  async loadFromFs(): Promise<void> {
    if (!this.fs) return;
    try {
      const content = await this.fs.readFile();
      if (content) {
        this.records = JSON.parse(content);
      }
    } catch {
      // 文件不存在或解析失败，保持空记录
    }
  }

  /** 手动捕获异常（已处理的错误）。 */
  captureException(error: unknown, context?: Record<string, unknown>): void {
    this.recordCrash({
      timestamp: new Date().toISOString(),
      message: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
      source: 'handled',
      context,
    });
  }

  /** 捕获消息。 */
  captureMessage(message: string, level: 'info' | 'warning' | 'error' = 'info'): void {
    if (this.sentry) {
      this.sentry.captureMessage(message, level);
    }
    logger[level === 'error' ? 'error' : level === 'warning' ? 'warn' : 'info']('crash', message);
  }

  /** 获取所有崩溃记录（错误恢复 UI 用）。 */
  getRecords(): CrashRecord[] {
    return [...this.records];
  }

  /** 获取最近的崩溃记录（错误恢复 UI 展示）。 */
  getLatestCrash(): CrashRecord | null {
    return this.records.length > 0 ? this.records[this.records.length - 1] : null;
  }

  /** 清空记录。 */
  clear(): void {
    this.records = [];
    this.persistToFs();
  }

  /** 导出崩溃日志为文本（用户可分享给开发者）。 */
  exportAsText(): string {
    return this.records.map(r =>
      `[${r.timestamp}] [${r.source}] ${r.message}\n${r.stack ?? ''}\n${r.context ? JSON.stringify(r.context) : ''}`,
    ).join('\n---\n');
  }
}

/** 文件系统抽象（使 CrashReporter 可单测）。 */
export interface CrashFs {
  readFile(): Promise<string>;
  writeFile(content: string): Promise<void>;
}

/** 全局崩溃上报单例。 */
export const crashReporter = new CrashReporter();

/** 错误恢复 UI 数据（plan.md「9.6 错误恢复 UI」）。 */
export interface ErrorRecoveryData {
  title: string;
  message: string;
  stack?: string;
  actions: {
    label: string;
    type: 'retry' | 'clear-cache' | 'export-logs' | 'restart';
  }[];
}

/** 构造错误恢复 UI 数据。 */
export function buildErrorRecoveryData(error: unknown): ErrorRecoveryData {
  const message = error instanceof Error ? error.message : String(error);
  const stack = error instanceof Error ? error.stack : undefined;
  return {
    title: '应用遇到问题',
    message,
    stack,
    actions: [
      { label: '重试', type: 'retry' },
      { label: '清除缓存并重启', type: 'clear-cache' },
      { label: '导出日志', type: 'export-logs' },
    ],
  };
}

/** 模拟 Sentry 桥接（测试用）。 */
export class MockSentryBridge implements SentryBridge {
  public initialized = false;
  public exceptions: unknown[] = [];
  public messages: string[] = [];

  init(): void { this.initialized = true; }
  captureException(error: unknown): void { this.exceptions.push(error); }
  captureMessage(message: string): void { this.messages.push(message); }
}
