import { PriorityRulesService } from './priority-rules.service';

describe('PriorityRulesService', () => {
  let service: PriorityRulesService;

  beforeEach(() => {
    service = new PriorityRulesService();
  });

  // ── computePriorityRules ──

  describe('computePriorityRules', () => {
    it('null profile → all defaults', () => {
      const rules = service.computePriorityRules(null, null, 'material', 'm1');
      expect(rules.depthPreference).toBe('standard');
      expect(rules.learningGoal).toBeNull();
      expect(rules.hasExamTarget).toBe(false);
      expect(rules.daysUntilDeadline).toBeNull();
      expect(rules.isTimeConstrained).toBe(false);
      expect(rules.dailyAvailableMinutes).toBeNull();
      expect(rules.isBudgetConstrained).toBe(false);
    });

    it('null settings → isBudgetConstrained=false', () => {
      const rules = service.computePriorityRules(
        { qualityPreference: 'deep' },
        null,
        'material',
        'm1',
      );
      expect(rules.isBudgetConstrained).toBe(false);
    });

    it('exam mode with deadline → hasExamTarget + daysUntilDeadline computed', () => {
      const future = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
      const rules = service.computePriorityRules(
        {
          qualityPreference: 'exam',
          examTarget: 'AWS Solutions Architect',
          learningDeadline: future,
        },
        null,
        'material',
        'm1',
      );
      expect(rules.depthPreference).toBe('exam');
      expect(rules.hasExamTarget).toBe(true);
      expect(rules.daysUntilDeadline).toBeGreaterThanOrEqual(9);
      expect(rules.daysUntilDeadline).toBeLessThanOrEqual(10);
    });

    it('deadline as ISO string → daysUntilDeadline computed correctly', () => {
      const futureStr = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000).toISOString();
      const rules = service.computePriorityRules(
        { examTarget: 'test', learningDeadline: futureStr },
        null,
        'material',
        'm1',
      );
      expect(rules.daysUntilDeadline).toBeGreaterThanOrEqual(9);
      expect(rules.daysUntilDeadline).toBeLessThanOrEqual(10);
    });

    it('deadline already expired → daysUntilDeadline=0', () => {
      const past = new Date(Date.now() - 5 * 24 * 60 * 60 * 1000);
      const rules = service.computePriorityRules(
        { examTarget: 'test', learningDeadline: past },
        null,
        'material',
        'm1',
      );
      expect(rules.daysUntilDeadline).toBe(0);
    });

    it('dailyAvailableMinutes=10 → isTimeConstrained=true', () => {
      const rules = service.computePriorityRules(
        { dailyAvailableMinutes: 10 },
        null,
        'material',
        'm1',
      );
      expect(rules.isTimeConstrained).toBe(true);
    });

    it('dailyAvailableMinutes=20 → isTimeConstrained=false', () => {
      const rules = service.computePriorityRules(
        { dailyAvailableMinutes: 20 },
        null,
        'material',
        'm1',
      );
      expect(rules.isTimeConstrained).toBe(false);
    });

    it('qualityPreference=light → taskSuitability only lightReview=true, rest restricted', () => {
      const rules = service.computePriorityRules(
        { qualityPreference: 'light' },
        null,
        'material',
        'm1',
      );
      expect(rules.taskSuitability.lightReview).toBe(true);
      expect(rules.taskSuitability.deepAnalysis).toBe(false);
      expect(rules.taskSuitability.quizGeneration).toBe(false);
      expect(rules.taskSuitability.flashcardGeneration).toBe(false);
      expect(rules.taskSuitability.contentSummarization).toBe(false);
    });

    it('qualityPreference=light with examTarget → quiz/flashcard enabled despite light mode', () => {
      const rules = service.computePriorityRules(
        { qualityPreference: 'light', examTarget: 'Exam' },
        null,
        'material',
        'm1',
      );
      expect(rules.taskSuitability.quizGeneration).toBe(true);
      expect(rules.taskSuitability.flashcardGeneration).toBe(true);
      expect(rules.taskSuitability.deepAnalysis).toBe(false);
    });

    it('deadline within 14 days + examTarget → urgentExamMode=true', () => {
      const future = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
      const rules = service.computePriorityRules(
        { examTarget: 'Exam', learningDeadline: future },
        null,
        'material',
        'm1',
      );
      expect(rules.taskSuitability.urgentExamMode).toBe(true);
    });

    it('deadline 30 days away → urgentExamMode=false', () => {
      const future = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
      const rules = service.computePriorityRules(
        { examTarget: 'Exam', learningDeadline: future },
        null,
        'material',
        'm1',
      );
      expect(rules.taskSuitability.urgentExamMode).toBe(false);
    });

    it('unknown qualityPreference → falls back to standard with warning', () => {
      const rules = service.computePriorityRules(
        { qualityPreference: 'fast' },
        null,
        'material',
        'm1',
      );
      expect(rules.depthPreference).toBe('standard');
    });

    it('maxDailyAiJobs=3 → isBudgetConstrained=true', () => {
      const rules = service.computePriorityRules(
        null,
        { maxDailyAiJobs: 3 },
        'material',
        'm1',
      );
      expect(rules.isBudgetConstrained).toBe(true);
    });

    it('maxDailyTokenBudget=5000 → isBudgetConstrained=true', () => {
      const rules = service.computePriorityRules(
        null,
        { maxDailyTokenBudget: 5000 },
        'material',
        'm1',
      );
      expect(rules.isBudgetConstrained).toBe(true);
    });

    it('knowledge_base scope enables contentSummarization for deep mode', () => {
      const rules = service.computePriorityRules(
        { qualityPreference: 'deep' },
        null,
        'knowledge_base',
        'kb1',
      );
      expect(rules.taskSuitability.contentSummarization).toBe(true);
    });

    it('material scope disables contentSummarization even for deep mode', () => {
      const rules = service.computePriorityRules(
        { qualityPreference: 'deep' },
        null,
        'material',
        'm1',
      );
      expect(rules.taskSuitability.contentSummarization).toBe(false);
    });

    it('learningGoal is passed through', () => {
      const rules = service.computePriorityRules(
        { learningGoal: 'Pass AWS exam' },
        null,
        'material',
        'm1',
      );
      expect(rules.learningGoal).toBe('Pass AWS exam');
    });
  });

  // ── computeTaskSuitability matrix ──

  describe('taskSuitability matrix', () => {
    const qualities = ['light', 'standard', 'deep', 'exam'] as const;

    it.each(qualities)('%s without time constraint → correct suitability', (qp) => {
      const rules = service.computePriorityRules(
        { qualityPreference: qp, dailyAvailableMinutes: 30 },
        null,
        'material',
        'm1',
      );

      expect(rules.taskSuitability.lightReview).toBe(true);
      expect(rules.taskSuitability.deepAnalysis).toBe(qp !== 'light');
      expect(rules.taskSuitability.quizGeneration).toBe(qp !== 'light');
      expect(rules.taskSuitability.flashcardGeneration).toBe(qp !== 'light');
      expect(rules.taskSuitability.contentSummarization).toBe(false); // material scope
      expect(rules.taskSuitability.urgentExamMode).toBe(false); // no exam
    });

    it.each(qualities)('%s with time constraint (10 min) → correct suitability', (qp) => {
      const rules = service.computePriorityRules(
        { qualityPreference: qp, dailyAvailableMinutes: 10 },
        null,
        'material',
        'm1',
      );

      expect(rules.isTimeConstrained).toBe(true);
      expect(rules.taskSuitability.lightReview).toBe(true);
      expect(rules.taskSuitability.deepAnalysis).toBe(false); // time-constrained → no deep
      expect(rules.taskSuitability.quizGeneration).toBe(qp !== 'light');
      expect(rules.taskSuitability.flashcardGeneration).toBe(qp !== 'light');
    });
  });
});
