/**
 * NotificationChannel LRU 批量淘汰 & Logger 队列上限测试。
 * 验证 #6/#20 修复。
 */
import { describe, expect, it, beforeEach } from 'vitest';
import { NotificationChannel, SimulatedNotificationListener, type NotificationEvent } from '../src/services/notification';
import { LoggerImpl } from '../src/utils/logger';

// ============ NotificationChannel LRU 批量淘汰 ============

describe('NotificationChannel LRU 批量淘汰 (#6)', () => {
  let channel: NotificationChannel;
  let listener: SimulatedNotificationListener;

  beforeEach(() => {
    listener = new SimulatedNotificationListener();
    // 使用自定义白名单包含测试包名
    channel = new NotificationChannel(listener, ['com.tencent.mm', 'com.test.app']);
  });

  it('正常去重：相同通知只处理一次', () => {
    const event: NotificationEvent = {
      packageName: 'com.tencent.mm',
      title: '微信支付',
      text: '微信支付 金额 10.00 商户:星巴克',
      timestamp: Date.now(),
    };

    const result1 = channel.handleNotification(event);
    expect(result1.processed).toBe(true);

    const result2 = channel.handleNotification(event);
    expect(result2.processed).toBe(false);
    expect(result2.reason).toContain('MD5');
  });

  it('LRU 批量淘汰：超过 1000 条时裁剪到 800', () => {
    // 注入 1001 条不同的通知（使用白名单包名）
    for (let i = 0; i < 1001; i++) {
      const event: NotificationEvent = {
        packageName: 'com.tencent.mm',
        title: `微信支付 ${i}`,
        text: `微信支付 金额 ${i}.00 商户:测试${i}`,
        timestamp: Date.now() + i,
      };
      channel.handleNotification(event);
    }

    // 验证缓存大小被限制（通过行为验证：新事件仍可处理）
    const newEvent: NotificationEvent = {
      packageName: 'com.tencent.mm',
      title: '微信支付 新事件',
      text: '微信支付 金额 999.00 商户:新商户',
      timestamp: Date.now() + 2000,
    };

    const result = channel.handleNotification(newEvent);
    expect(result.processed).toBe(true);
  });

  it('LRU 淘汰后保留较新的记录', () => {
    // 注入 1001 条
    for (let i = 0; i < 1001; i++) {
      const event: NotificationEvent = {
        packageName: 'com.tencent.mm',
        title: `微信支付 ${i}`,
        text: `微信支付 金额 ${i}.00`,
        timestamp: Date.now() + i,
      };
      channel.handleNotification(event);
    }

    // 第 1000 条（最新的）应该还在缓存中
    const lastEvent: NotificationEvent = {
      packageName: 'com.tencent.mm',
      title: '微信支付 1000',
      text: '微信支付 金额 1000.00',
      timestamp: Date.now() + 1000,
    };

    const result = channel.handleNotification(lastEvent);
    expect(result.processed).toBe(false); // 仍然是重复
    expect(result.reason).toContain('MD5');
  });
});

// ============ Logger 队列上限 ============

describe('Logger 队列上限 (#20)', () => {
  it('队列超过 MAX_QUEUE_SIZE 时丢弃最旧条目', () => {
    const logger = new LoggerImpl(100);
    logger.consoleOutput = false;

    // 模拟一个总是失败的后端
    const failingBackend = {
      appendLog: async () => { throw new Error('写入失败'); },
      readLogFile: async () => '',
      listLogFiles: async () => [],
      deleteLogFile: async () => {},
      clearAllLogFiles: async () => {},
    };

    // 同步初始化后端（不等待清理）
    logger.initFileBackend(failingBackend);

    // 写入超过 5000 条日志
    for (let i = 0; i < 5100; i++) {
      logger.info('test', `消息 ${i}`);
    }

    // 队列不应该无限增长
    // 由于是私有属性，我们通过行为验证：flushQueue 不会处理超过 5000 条
    // 这里主要验证不会抛出 OOM 错误
    expect(true).toBe(true);
  });

  it('正常写入时队列按日期分组写入', async () => {
    const logger = new LoggerImpl(100);
    logger.consoleOutput = false;

    const writtenLines: string[] = [];
    const successBackend = {
      appendLog: async (_date: string, line: string) => { writtenLines.push(line); },
      readLogFile: async () => '',
      listLogFiles: async () => [],
      deleteLogFile: async () => {},
      clearAllLogFiles: async () => {},
    };

    await logger.initFileBackend(successBackend);

    // 写入少量日志
    for (let i = 0; i < 10; i++) {
      logger.info('test', `消息 ${i}`);
    }

    // 刷新队列
    await logger.flushQueue();

    // 同一天的日志会被合并为一次写入（按日期分组）
    expect(writtenLines.length).toBe(1);
    // 但内容包含所有 10 条日志
    expect(writtenLines[0]).toContain('消息 0');
    expect(writtenLines[0]).toContain('消息 9');
  });

  it('内存缓冲区循环淘汰正常工作', () => {
    const logger = new LoggerImpl(5); // 小缓冲区
    logger.consoleOutput = false;

    for (let i = 0; i < 10; i++) {
      logger.info('test', `消息 ${i}`);
    }

    const logs = logger.getLogs();
    expect(logs.length).toBe(5);
    // 应该保留最新的 5 条
    expect(logs[0].message).toBe('消息 5');
    expect(logs[4].message).toBe('消息 9');
  });
});
