/**
 * 带有磁盘持久化与可配置后端的日志系统（plan.md「0.6 日志系统」）。
 *
 * - 4 级日志（DEBUG/INFO/WARN/ERROR）
 * - 循环内存缓冲（默认 1000 条），供实时 UI 显示
 * - 支持扩展 LogFileBackend 接口，持久化到手机本地磁盘（按日期保存日志文件）
 * - 支持日志筛选、历史日志加载、日志文件过期清理（默认保留 7 天）与文本导出
 */

export enum LogLevel {
  DEBUG = 0,
  INFO = 1,
  WARN = 2,
  ERROR = 3,
}

export interface LogEntry {
  timestamp: string;  // ISO 时间戳
  level: LogLevel;
  tag: string;        // 模块标识（如 'mobileStore'、'billPipeline'）
  message: string;
  data?: unknown;
}

export interface LogFileInfo {
  name: string;      // 文件名，例如 'app-2026-07-22.log'
  path: string;      // 文件完整路径/URI
  size: number;      // 字节大小
  date: string;      // 日期字符串 YYYY-MM-DD
}

/** 磁盘日志持久化后端抽象（解耦 React Native / Expo 文件系统）。 */
export interface LogFileBackend {
  appendLog(dateStr: string, logLine: string): Promise<void>;
  readLogFile(dateStr: string): Promise<string>;
  listLogFiles(): Promise<LogFileInfo[]>;
  deleteLogFile(dateStr: string): Promise<void>;
  clearAllLogFiles(): Promise<void>;
}

export class LoggerImpl {
  private buffer: LogEntry[] = [];
  private maxBuffer: number;
  /** 最低输出级别（默认 DEBUG，生产环境可调高）。 */
  minLevel: LogLevel = LogLevel.DEBUG;
  /** 是否输出到 console（开发环境 true）。 */
  consoleOutput: boolean = true;

  private fileBackend: LogFileBackend | null = null;
  private pendingWriteQueue: { dateStr: string; line: string }[] = [];
  private isFlushingQueue: boolean = false;
  private flushTimer: ReturnType<typeof setTimeout> | null = null;
  /** 写入队列上限，防止后端持续失败时队列无限增长导致 OOM。 */
  private static readonly MAX_QUEUE_SIZE = 5000;

  constructor(maxBuffer = 1000) {
    this.maxBuffer = maxBuffer;
  }

  /** 设置磁盘持久化后端。 */
  async initFileBackend(backend: LogFileBackend, options?: { maxDays?: number }): Promise<void> {
    this.fileBackend = backend;
    if (options?.maxDays) {
      await this.cleanExpiredLogFiles(options.maxDays);
    }
  }

  debug(tag: string, message: string, data?: unknown): void {
    this.log(LogLevel.DEBUG, tag, message, data);
  }

  info(tag: string, message: string, data?: unknown): void {
    this.log(LogLevel.INFO, tag, message, data);
  }

  warn(tag: string, message: string, data?: unknown): void {
    this.log(LogLevel.WARN, tag, message, data);
  }

  error(tag: string, message: string, data?: unknown): void {
    this.log(LogLevel.ERROR, tag, message, data);
  }

  private log(level: LogLevel, tag: string, message: string, data?: unknown): void {
    if (level < this.minLevel) return;

    const entry: LogEntry = {
      timestamp: new Date().toISOString(),
      level, tag, message, data,
    };

    this.buffer.push(entry);
    // 循环缓冲：超出上限丢弃最旧
    if (this.buffer.length > this.maxBuffer) {
      this.buffer.shift();
    }

    if (this.consoleOutput) {
      const prefix = `[${tag}]`;
      switch (level) {
        // eslint-disable-next-line no-console
        case LogLevel.DEBUG: console.log(prefix, message, data ?? ''); break;
        // eslint-disable-next-line no-console
        case LogLevel.INFO: console.info(prefix, message, data ?? ''); break;
        case LogLevel.WARN: console.warn(prefix, message, data ?? ''); break;
        case LogLevel.ERROR: console.error(prefix, message, data ?? ''); break;
      }
    }

    // 写入文件队列
    if (this.fileBackend) {
      const dateStr = entry.timestamp.slice(0, 10); // YYYY-MM-DD
      const line = JSON.stringify(entry);
      this.pendingWriteQueue.push({ dateStr, line });
      // 队列超限时丢弃最旧条目，防止后端持续失败时 OOM
      if (this.pendingWriteQueue.length > LoggerImpl.MAX_QUEUE_SIZE) {
        this.pendingWriteQueue.splice(0, this.pendingWriteQueue.length - LoggerImpl.MAX_QUEUE_SIZE);
      }
      this.scheduleQueueFlush();
    }
  }

  /** 防抖批量刷新写入文件。 */
  private scheduleQueueFlush(): void {
    if (this.flushTimer) return;
    this.flushTimer = setTimeout(() => {
      this.flushTimer = null;
      this.flushQueue().catch(() => {});
    }, 200);
  }

  /** 强制立即刷新文件写入队列。 */
  async flushQueue(): Promise<void> {
    if (!this.fileBackend || this.isFlushingQueue || this.pendingWriteQueue.length === 0) {
      return;
    }

    this.isFlushingQueue = true;
    const itemsToFlush = [...this.pendingWriteQueue];
    this.pendingWriteQueue = [];

    try {
      // 按日期分组写入
      const groupedByDate: Record<string, string[]> = {};
      for (const item of itemsToFlush) {
        if (!groupedByDate[item.dateStr]) {
          groupedByDate[item.dateStr] = [];
        }
        groupedByDate[item.dateStr].push(item.line);
      }

      for (const [dateStr, lines] of Object.entries(groupedByDate)) {
        await this.fileBackend.appendLog(dateStr, lines.join('\n') + '\n');
      }
    } catch {
      // 写入失败重试逻辑：将未成功写入的重新放回队列头部
      this.pendingWriteQueue.unshift(...itemsToFlush);
    } finally {
      this.isFlushingQueue = false;
    }
  }

  /** 获取内存中所有日志（副本）。 */
  getLogs(): LogEntry[] {
    return [...this.buffer];
  }

  /** 按级别/标签过滤内存日志。 */
  query(filter: { minLevel?: LogLevel; tag?: string; keyword?: string }): LogEntry[] {
    return this.buffer.filter(e => {
      if (filter.minLevel !== undefined && e.level < filter.minLevel) return false;
      if (filter.tag !== undefined && filter.tag !== '' && e.tag !== filter.tag) return false;
      if (filter.keyword) {
        const kw = filter.keyword.toLowerCase();
        const msgMatch = e.message.toLowerCase().includes(kw);
        const tagMatch = e.tag.toLowerCase().includes(kw);
        const dataMatch = e.data ? JSON.stringify(e.data).toLowerCase().includes(kw) : false;
        if (!msgMatch && !tagMatch && !dataMatch) return false;
      }
      return true;
    });
  }

  /** 清空内存日志。 */
  clearLogs(): void {
    this.buffer = [];
  }

  /** 清空内存与磁盘日志。 */
  async clearAllLogs(): Promise<void> {
    this.buffer = [];
    this.pendingWriteQueue = [];
    if (this.fileBackend) {
      await this.fileBackend.clearAllLogFiles();
    }
  }

  /** 调整内存缓冲上限。 */
  setMaxBuffer(size: number): void {
    this.maxBuffer = size;
    if (this.buffer.length > size) {
      this.buffer = this.buffer.slice(this.buffer.length - size);
    }
  }

  /** 获取所有日志文件列表。 */
  async getLogFiles(): Promise<LogFileInfo[]> {
    if (!this.fileBackend) return [];
    return this.fileBackend.listLogFiles();
  }

  /** 从文件读取特定日期的日志。 */
  async loadLogsFromFile(dateStr: string): Promise<LogEntry[]> {
    if (!this.fileBackend) return [];
    try {
      const content = await this.fileBackend.readLogFile(dateStr);
      if (!content.trim()) return [];

      const entries: LogEntry[] = [];
      const lines = content.split('\n');
      for (const line of lines) {
        const trimmed = line.trim();
        if (!trimmed) continue;
        try {
          const entry = JSON.parse(trimmed) as LogEntry;
          if (entry && entry.timestamp && entry.level !== undefined && entry.message) {
            entries.push(entry);
          }
        } catch {
          // 忽略非法数据行
        }
      }
      return entries;
    } catch {
      return [];
    }
  }

  /** 获取今天的全量日志（包含已被写入手机磁盘的历史日志 + 当前 Session 内存中的最新日志，自动去重）。 */
  async getTodayLogs(): Promise<LogEntry[]> {
    const todayStr = new Date().toISOString().slice(0, 10);
    const diskLogs = await this.loadLogsFromFile(todayStr);

    const seen = new Set<string>();
    const combined: LogEntry[] = [];

    for (const entry of diskLogs) {
      const key = `${entry.timestamp}_${entry.tag}_${entry.message}`;
      if (!seen.has(key)) {
        seen.add(key);
        combined.push(entry);
      }
    }

    for (const entry of this.buffer) {
      const key = `${entry.timestamp}_${entry.tag}_${entry.message}`;
      if (!seen.has(key)) {
        seen.add(key);
        combined.push(entry);
      }
    }

    return combined;
  }

  /** 清理超过 maxDays 天数的历史日志文件。 */
  async cleanExpiredLogFiles(maxDays = 7): Promise<void> {
    if (!this.fileBackend) return;
    try {
      const files = await this.fileBackend.listLogFiles();
      const cutoffTime = Date.now() - maxDays * 24 * 60 * 60 * 1000;

      for (const file of files) {
        const fileDate = new Date(file.date).getTime();
        if (!isNaN(fileDate) && fileDate < cutoffTime) {
          await this.fileBackend.deleteLogFile(file.date);
        }
      }
    } catch {
      // 静默处理清理错误
    }
  }

  /** 格式化日志列表为文本形式（可用于导出或分享）。 */
  exportAsFormattedText(entries?: LogEntry[]): string {
    const list = entries ?? this.buffer;
    if (list.length === 0) return '--- 无日志记录 ---';

    return list
      .map(e => {
        const levelName = LEVEL_LABELS[e.level] ?? 'INFO';
        const hasData = e.data !== undefined && e.data !== null && (typeof e.data !== 'object' || Object.keys(e.data).length > 0);
        const dataStr = hasData ? ` | Data: ${JSON.stringify(e.data)}` : '';
        return `[${e.timestamp}] [${levelName}] [${e.tag}] ${e.message}${dataStr}`;
      })
      .join('\n');
  }
}

/** 全局单例日志器。 */
export const logger = new LoggerImpl();

/** 工厂：创建独立实例（测试用，避免污染全局单例）。 */
export function createLogger(maxBuffer = 1000): LoggerImpl {
  return new LoggerImpl(maxBuffer);
}

/** LogLevel 标签（导出/显示用）。 */
export const LEVEL_LABELS: Record<LogLevel, string> = {
  [LogLevel.DEBUG]: 'DEBUG',
  [LogLevel.INFO]: 'INFO',
  [LogLevel.WARN]: 'WARN',
  [LogLevel.ERROR]: 'ERROR',
};

