import { Test, TestingModule } from '@nestjs/testing';
import { FeynmanObservabilityService } from './feynman-observability.service';

describe('FeynmanObservabilityService', () => {
  let obs: FeynmanObservabilityService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [FeynmanObservabilityService],
    }).compile();

    obs = module.get(FeynmanObservabilityService);
  });

  describe('结构化日志', () => {
    it('logRequest 不含用户解释和模型输出', () => {
      const log = {
        requestId: 'req-001',
        knowledgeItemId: 'ki-001',
        userId: 'u-001',
        engineMode: 'unified' as const,
        jobType: 'feynman_evaluation',
        queueName: 'ai-interactive',
        submissionId: 'sub-001',
      };
      // 不应抛错（Logger 内部调用）
      expect(() => obs.logRequest(log)).not.toThrow();
    });

    it('logJobCreated 记录 jobId 和队列名', () => {
      expect(() =>
        obs.logJobCreated({
          requestId: 'req-001',
          jobId: 'job-001',
          knowledgeItemId: 'ki-001',
          userId: 'u-001',
          engineMode: 'unified',
          jobType: 'feynman_evaluation',
          queueName: 'ai-interactive',
        }),
      ).not.toThrow();
    });

    it('logJobCreateFailed 记录错误但含用户标识', () => {
      expect(() =>
        obs.logJobCreateFailed(
          {
            requestId: 'req-001',
            knowledgeItemId: 'ki-001',
            userId: 'u-001',
            engineMode: 'unified',
            jobType: 'feynman_evaluation',
            queueName: 'ai-interactive',
          },
          'Snapshot build failed',
        ),
      ).not.toThrow();
    });

    it('logExecutionCompleted 含 focusItemCount 和 reviewCardCount', () => {
      expect(() =>
        obs.logExecutionCompleted({
          requestId: 'engine',
          jobId: 'job-001',
          knowledgeItemId: 'ki-001',
          userId: 'u-001',
          engineMode: 'unified',
          jobType: 'feynman_evaluation',
          queueName: 'ai-interactive',
          durationMs: 5000,
          lifecycleStatus: 'succeeded',
          attemptCount: 1,
          focusItemCount: 2,
          reviewCardCount: 0,
        }),
      ).not.toThrow();
    });

    it('logExecutionFailed 记录 errorCode 但不含内部堆栈', () => {
      expect(() =>
        obs.logExecutionFailed(
          {
            requestId: 'engine',
            jobId: 'job-001',
            knowledgeItemId: 'ki-001',
            userId: 'u-001',
            engineMode: 'unified',
            jobType: 'feynman_evaluation',
            queueName: 'ai-interactive',
            errorCode: 'provider_timeout',
          },
          'timeout',
        ),
      ).not.toThrow();
    });

    it('logRollback 记录回滚原因', () => {
      expect(() =>
        obs.logRollback('u-001', 'FEYNMAN_ENGINE_MODE set to legacy'),
      ).not.toThrow();
    });
  });

  describe('计数器操作', () => {
    it('初始值为 0', () => {
      const c = obs.getCounters();
      expect(c.legacyRequests).toBe(0);
      expect(c.unifiedRequests).toBe(0);
      expect(c.unifiedExecuteSuccess).toBe(0);
      expect(c.unifiedExecuteFailed).toBe(0);
      expect(c.projectorFailed).toBe(0);
      expect(c.focusItemCreated).toBe(0);
      expect(c.reviewCardCreated).toBe(0);
      expect(c.rollbackCount).toBe(0);
    });

    it('incrementLegacyRequests', () => {
      obs.incrementLegacyRequests();
      obs.incrementLegacyRequests();
      expect(obs.getCounters().legacyRequests).toBe(2);
    });

    it('incrementUnifiedRequests', () => {
      obs.incrementUnifiedRequests();
      expect(obs.getCounters().unifiedRequests).toBe(1);
    });

    it('incrementUnifiedExecuteSuccess 累加 duration 和 count', () => {
      obs.incrementUnifiedExecuteSuccess(3000);
      obs.incrementUnifiedExecuteSuccess(7000);
      const c = obs.getCounters();
      expect(c.unifiedExecuteSuccess).toBe(2);
      expect(c.unifiedAvgDurationMs).toBe(5000); // (3000+7000)/2
    });

    it('incrementUnifiedExecuteFailed', () => {
      obs.incrementUnifiedExecuteFailed();
      obs.incrementUnifiedExecuteFailed();
      expect(obs.getCounters().unifiedExecuteFailed).toBe(2);
    });

    it('incrementUnifiedRetry', () => {
      obs.incrementUnifiedRetry();
      expect(obs.getCounters().unifiedRetryCount).toBe(1);
    });

    it('incrementProjectorFailed', () => {
      obs.incrementProjectorFailed();
      expect(obs.getCounters().projectorFailed).toBe(1);
    });

    it('addFocusItemCreated 累加', () => {
      obs.addFocusItemCreated(3);
      obs.addFocusItemCreated(2);
      expect(obs.getCounters().focusItemCreated).toBe(5);
    });

    it('addReviewCardCreated 累加', () => {
      obs.addReviewCardCreated(1);
      expect(obs.getCounters().reviewCardCreated).toBe(1);
    });

    it('incrementRollback', () => {
      obs.incrementRollback();
      expect(obs.getCounters().rollbackCount).toBe(1);
    });
  });

  describe('resetCounters', () => {
    it('重置所有计数器', () => {
      obs.incrementLegacyRequests();
      obs.incrementUnifiedRequests();
      obs.incrementUnifiedExecuteSuccess(1000);
      obs.addFocusItemCreated(5);

      obs.resetCounters();

      const c = obs.getCounters();
      expect(c.legacyRequests).toBe(0);
      expect(c.unifiedRequests).toBe(0);
      expect(c.unifiedExecuteSuccess).toBe(0);
      expect(c.focusItemCreated).toBe(0);
      expect(c.unifiedAvgDurationMs).toBe(0);
    });
  });

  describe('getCounters', () => {
    it('unifiedAvgDurationMs 在无成功执行时为 0', () => {
      obs.incrementUnifiedExecuteFailed();
      expect(obs.getCounters().unifiedAvgDurationMs).toBe(0);
    });

    it('返回所有计数器快照', () => {
      obs.incrementLegacyRequests();
      obs.incrementUnifiedRequests();
      const c = obs.getCounters();
      expect(c).toHaveProperty('legacyRequests');
      expect(c).toHaveProperty('unifiedRequests');
      expect(c).toHaveProperty('unifiedCreateFailed');
      expect(c).toHaveProperty('unifiedExecuteSuccess');
      expect(c).toHaveProperty('unifiedExecuteFailed');
      expect(c).toHaveProperty('unifiedAvgDurationMs');
      expect(c).toHaveProperty('unifiedRetryCount');
      expect(c).toHaveProperty('projectorFailed');
      expect(c).toHaveProperty('focusItemCreated');
      expect(c).toHaveProperty('reviewCardCreated');
      expect(c).toHaveProperty('rollbackCount');
    });
  });
});
