/**
 * reviewStateMachine.ts 단위 테스트
 *
 * 테스트 대상:
 *  - isValidTransition   : 상태 전이 유효성 검사
 *  - transitionStatus    : 상태 전이 실행
 *  - assessRiskLevel     : 리스크 레벨 판정
 *  - getRequiredApprovals: 승인 요건 조회
 *  - canApprove          : 승인 가능 여부 판단
 *
 * vitest로 실행 (nextapp/vitest.config.ts가 ../functions/src/**를 포함)
 */

import { describe, it, expect } from 'vitest';
import {
  isValidTransition,
  transitionStatus,
  assessRiskLevel,
  getRequiredApprovals,
  canApprove,
} from '../reviewStateMachine';

// ── 합법 전이 테스트 ─────────────────────────────────────────────────────────

describe('isValidTransition - 합법 전이 (6건)', () => {
  it('1. draft → in_review 가능', () => {
    expect(isValidTransition('draft', 'in_review')).toBe(true);
  });

  it('2. in_review → approved 가능', () => {
    expect(isValidTransition('in_review', 'approved')).toBe(true);
  });

  it('3. in_review → rejected 가능', () => {
    expect(isValidTransition('in_review', 'rejected')).toBe(true);
  });

  it('4. in_review → revision_requested 가능', () => {
    expect(isValidTransition('in_review', 'revision_requested')).toBe(true);
  });

  it('5. approved → needs_re_review 가능', () => {
    expect(isValidTransition('approved', 'needs_re_review')).toBe(true);
  });

  it('6. rejected → draft 가능', () => {
    expect(isValidTransition('rejected', 'draft')).toBe(true);
  });

  it('6a. revision_requested → draft 가능', () => {
    expect(isValidTransition('revision_requested', 'draft')).toBe(true);
  });

  it('6b. revision_requested → in_review 가능', () => {
    expect(isValidTransition('revision_requested', 'in_review')).toBe(true);
  });

  it('6c. needs_re_review → in_review 가능', () => {
    expect(isValidTransition('needs_re_review', 'in_review')).toBe(true);
  });

  it('6d. published → needs_re_review 가능', () => {
    expect(isValidTransition('published', 'needs_re_review')).toBe(true);
  });
});

// ── 불법 전이 테스트 ─────────────────────────────────────────────────────────

describe('isValidTransition - 불법 전이 (6건)', () => {
  it('7. draft → approved 불가 (리뷰 없이 직접 승인 불가)', () => {
    expect(isValidTransition('draft', 'approved')).toBe(false);
  });

  it('8. draft → rejected 불가 (리뷰 없이 거절 불가)', () => {
    expect(isValidTransition('draft', 'rejected')).toBe(false);
  });

  it('9. in_review → draft 불가 (리뷰 중 초안 복귀 불가)', () => {
    expect(isValidTransition('in_review', 'draft')).toBe(false);
  });

  it('10. approved → draft 불가 (승인 후 초안 불가)', () => {
    expect(isValidTransition('approved', 'draft')).toBe(false);
  });

  it('11. rejected → approved 불가 (거절에서 직접 승인 불가)', () => {
    expect(isValidTransition('rejected', 'approved')).toBe(false);
  });

  it('12. published → approved 불가 (published에서 직접 승인 불가)', () => {
    expect(isValidTransition('published', 'approved')).toBe(false);
  });
});

// ── transitionStatus 테스트 ─────────────────────────────────────────────────

describe('transitionStatus', () => {
  it('유효한 전이는 targetStatus를 반환', () => {
    expect(transitionStatus('draft', 'in_review')).toBe('in_review');
  });

  it('무효한 전이는 Error를 throw', () => {
    expect(() => transitionStatus('draft', 'approved')).toThrow();
  });

  it('throw된 에러 메시지에 전이 정보가 포함', () => {
    expect(() => transitionStatus('approved', 'draft')).toThrow(/approved.*draft/);
  });
});

// ── assessRiskLevel 테스트 ─────────────────────────────────────────────────

describe('assessRiskLevel - 리스크 레벨 판정 (4건)', () => {
  it('13. court_ruling → high', () => {
    expect(assessRiskLevel('court_ruling')).toBe('high');
  });

  it('14. regulation → high', () => {
    expect(assessRiskLevel('regulation')).toBe('high');
  });

  it('15. policy_pdf → high', () => {
    expect(assessRiskLevel('policy_pdf')).toBe('high');
  });

  it('16. newsletter → low', () => {
    expect(assessRiskLevel('newsletter')).toBe('low');
  });

  it('sourceType 없으면 low', () => {
    expect(assessRiskLevel(undefined)).toBe('low');
  });

  it('알 수 없는 sourceType은 low', () => {
    expect(assessRiskLevel('unknown_type')).toBe('low');
  });
});

// ── getRequiredApprovals 테스트 ──────────────────────────────────────────────

describe('getRequiredApprovals', () => {
  it('low risk: reviewerCount=1, requiresAdmin=false', () => {
    const result = getRequiredApprovals('low');
    expect(result).toEqual({ reviewerCount: 1, requiresAdmin: false });
  });

  it('high risk: reviewerCount=1, requiresAdmin=true', () => {
    const result = getRequiredApprovals('high');
    expect(result).toEqual({ reviewerCount: 1, requiresAdmin: true });
  });
});

// ── canApprove 테스트 ────────────────────────────────────────────────────────

describe('canApprove - 승인 가능 여부', () => {
  it('17. low risk: reviewer 1명 approve → canApprove true', () => {
    const reviews = [{ decision: 'approve', reviewerId: 'r1', reviewerRole: 'reviewer' }];
    expect(canApprove('low', reviews)).toBe(true);
  });

  it('18. high risk: reviewer approve만 있으면 → canApprove false', () => {
    const reviews = [{ decision: 'approve', reviewerId: 'r1', reviewerRole: 'reviewer' }];
    expect(canApprove('high', reviews)).toBe(false);
  });

  it('19. high risk: reviewer approve + admin approve → canApprove true', () => {
    const reviews = [
      { decision: 'approve', reviewerId: 'r1', reviewerRole: 'reviewer' },
      { decision: 'approve', reviewerId: 'a1', reviewerRole: 'admin' },
    ];
    expect(canApprove('high', reviews)).toBe(true);
  });

  it('20. low risk: 0 approves → canApprove false', () => {
    const reviews: Array<{ decision: string; reviewerId: string; reviewerRole?: string }> = [];
    expect(canApprove('low', reviews)).toBe(false);
  });

  it('high risk: admin approve만 있으면 → canApprove false (reviewer approve 필요)', () => {
    const reviews = [{ decision: 'approve', reviewerId: 'a1', reviewerRole: 'admin' }];
    expect(canApprove('high', reviews)).toBe(false);
  });

  it('low risk: reject 결정만 있으면 → canApprove false', () => {
    const reviews = [{ decision: 'reject', reviewerId: 'r1', reviewerRole: 'reviewer' }];
    expect(canApprove('low', reviews)).toBe(false);
  });

  it('high risk: admin 먼저 approve + reviewer 나중 approve → canApprove true (순서 무관)', () => {
    const reviews = [
      { decision: 'approve', reviewerId: 'a1', reviewerRole: 'admin' },
      { decision: 'approve', reviewerId: 'r1', reviewerRole: 'reviewer' },
    ];
    expect(canApprove('high', reviews)).toBe(true);
  });
});
