import { Test, TestingModule } from '@nestjs/testing';
import { LearningAnalysisValidator, BusinessValidationError } from './learning-analysis-validator';

function validOutput(overrides?: any) {
  return {
    summary: '学习表现良好，复习完成率较高',
    strengths: [
      { title: '复习完成率高', description: '完成率达到85%', evidenceRefs: [{ sourceType: 'review_metric' as const, metricKey: 'reviewAccuracy' }] },
    ],
    weaknesses: [
      { title: '主动回忆不足', description: '近30天仅2次', knowledgePointId: null, evidenceRefs: [{ sourceType: 'active_recall' as const, metricKey: 'count' }] },
    ],
    trends: [
      { metricKey: 'totalStudyDuration', direction: 'stable' as const, description: '学习时长稳定', evidenceRefs: [{ sourceType: 'study_metric' as const, metricKey: 'totalStudyDuration' }] },
    ],
    risks: [
      { title: '遗忘风险', severity: 'medium' as const, description: '3个知识点已过期', evidenceRefs: [{ sourceType: 'review_metric' as const, metricKey: 'overdueCount' }] },
    ],
    recommendations: [
      { actionType: 'active_recall', title: '增加主动回忆', reason: '最有效的策略', priority: 5, evidenceRefs: [{ sourceType: 'active_recall' as const, metricKey: 'count' }] },
    ],
    confidence: 0.75,
    insufficientData: false,
    ...overrides,
  };
}

describe('LearningAnalysisValidator', () => {
  let validator: LearningAnalysisValidator;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [LearningAnalysisValidator],
    }).compile();
    validator = module.get(LearningAnalysisValidator);
    jest.spyOn(require('@nestjs/common').Logger.prototype, 'log').mockImplementation(() => {});
    jest.spyOn(require('@nestjs/common').Logger.prototype, 'warn').mockImplementation(() => {});
  });

  describe('正常输出', () => {
    it('合法输出通过', () => {
      expect(() => validator.validate(validOutput())).not.toThrow();
    });
  });

  describe('Schema 验证', () => {
    it('summary 必填', () => {
      expect(() => validator.validate(validOutput({ summary: '' }))).toThrow(BusinessValidationError);
    });
    it('strengths 上限 3', () => {
      const s = Array(4).fill({ title: 'S', description: 'D', evidenceRefs: [{ sourceType: 'study_metric', metricKey: 'm' }] });
      expect(() => validator.validate(validOutput({ strengths: s }))).toThrow(BusinessValidationError);
    });
    it('weaknesses 上限 5', () => {
      const w = Array(6).fill({ title: 'W', description: 'D', evidenceRefs: [{ sourceType: 'study_metric', metricKey: 'm' }] });
      expect(() => validator.validate(validOutput({ weaknesses: w }))).toThrow(BusinessValidationError);
    });
    it('recommendations 非空', () => {
      expect(() => validator.validate(validOutput({ recommendations: [] }))).toThrow(BusinessValidationError);
    });
    it('confidence 超出 [0,1]', () => {
      expect(() => validator.validate(validOutput({ confidence: 1.5 }))).toThrow(BusinessValidationError);
    });
  });

  describe('Evidence 验证', () => {
    it('非法 sourceType', () => {
      const s = [{ title: 'S', description: 'D', evidenceRefs: [{ sourceType: 'unknown_type', metricKey: 'x' }] }];
      expect(() => validator.validate(validOutput({ strengths: s }))).toThrow(BusinessValidationError);
    });
    it('缺失 metricKey', () => {
      const s = [{ title: 'S', description: 'D', evidenceRefs: [{ sourceType: 'study_metric', metricKey: '' }] }];
      expect(() => validator.validate(validOutput({ strengths: s }))).toThrow(BusinessValidationError);
    });
    it('strength 无 evidenceRefs', () => {
      const s = [{ title: 'S', description: 'D', evidenceRefs: [] }];
      expect(() => validator.validate(validOutput({ strengths: s }))).toThrow(BusinessValidationError);
    });
    it('weakness 无 evidenceRefs', () => {
      const w = [{ title: 'W', description: 'D', evidenceRefs: [] }];
      expect(() => validator.validate(validOutput({ weaknesses: w }))).toThrow(BusinessValidationError);
    });
  });

  describe('Business 验证', () => {
    it('insufficientData=true 但 confidence>0.5', () => {
      expect(() => validator.validate(validOutput({ insufficientData: true, confidence: 0.8 }))).toThrow(BusinessValidationError);
    });
    it('insufficientData=true 且 confidence 低 → 通过', () => {
      expect(() => validator.validate(validOutput({ insufficientData: true, confidence: 0.3 }))).not.toThrow();
    });
  });

  describe('医疗诊断', () => {
    it('summary 含 ADHD', () => {
      expect(() => validator.validate(validOutput({ summary: '用户可能患有ADHD' }))).toThrow(BusinessValidationError);
    });
    it('description 含 depression', () => {
      const s = [{ title: 'S', description: 'signs of depression detected', evidenceRefs: [{ sourceType: 'study_metric', metricKey: 'm' }] }];
      expect(() => validator.validate(validOutput({ strengths: s }))).toThrow(BusinessValidationError);
    });
    it('含 焦虑症', () => {
      expect(() => validator.validate(validOutput({ summary: '表现出焦虑症倾向' }))).toThrow(BusinessValidationError);
    });
    it('含 PTSD', () => {
      expect(() => validator.validate(validOutput({ summary: '可能有PTSD症状' }))).toThrow(BusinessValidationError);
    });
  });

  describe('人格判断', () => {
    it('含 "你是一个...的人"', () => {
      expect(() => validator.validate(validOutput({ summary: '你是一个懒惰的人' }))).toThrow(BusinessValidationError);
    });
    it('含 "你天生"', () => {
      expect(() => validator.validate(validOutput({ summary: '你天生不适合学习' }))).toThrow(BusinessValidationError);
    });
    it('含 "你太懒"', () => {
      const r = [{ actionType: 'study', title: '加油', reason: '因为你太懒了', priority: 1, evidenceRefs: [{ sourceType: 'study_metric', metricKey: 'm' }] }];
      expect(() => validator.validate(validOutput({ recommendations: r }))).toThrow(BusinessValidationError);
    });
  });

  describe('Markdown 代码块', () => {
    it('summary 含 code block', () => {
      expect(() => validator.validate(validOutput({ summary: '分析结果：\n```json\n{}\n```' }))).toThrow(BusinessValidationError);
    });
  });
});
