import { describe, it, expect } from 'vitest';
import { RecordReviewCompletionUseCase } from '@/modules/tracking/usecases/tracking/recordReviewCompletion.usecase.js';
import { InMemoryReviewRequestTrackingGateway } from '../../../stubs/reviewRequestTracking.stub.js';
import { TrackedMrFactory } from '../../../factories/trackedMr.factory.js';
import { DiffStatsFactory } from '@/tests/factories/diffStats.factory.js';

describe('RecordReviewCompletionUseCase', () => {
  const reviewData = {
    type: 'review' as const,
    durationMs: 60000,
    score: 8,
    blocking: 2,
    warnings: 3,
    suggestions: 1,
    threadsOpened: 2,
    threadsClosed: 0,
  };

  it('should record review event and update aggregates', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({ id: 'mr-1' });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({ projectPath: '/project', mrId: 'mr-1', reviewData });

    expect(result).not.toBeNull();
    expect(result?.reviews).toHaveLength(1);
    expect(result?.totalReviews).toBe(1);
    expect(result?.totalBlocking).toBe(2);
    expect(result?.totalWarnings).toBe(3);
    expect(result?.totalSuggestions).toBe(1);
    expect(result?.totalDurationMs).toBe(60000);
    expect(result?.latestScore).toBe(8);
  });

  it('should transition to pending-fix when blocking issues exist', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({ id: 'mr-1', state: 'pending-review' });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({
      projectPath: '/project',
      mrId: 'mr-1',
      reviewData: { ...reviewData, blocking: 1 },
    });

    expect(result?.state).toBe('pending-fix');
  });

  it('should transition to pending-approval when no blocking issues', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({ id: 'mr-1', state: 'pending-review', openThreads: 0 });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({
      projectPath: '/project',
      mrId: 'mr-1',
      reviewData: { ...reviewData, blocking: 0, threadsOpened: 0 },
    });

    expect(result?.state).toBe('pending-approval');
  });

  it('should track open threads from review', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({ id: 'mr-1', openThreads: 1 });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({
      projectPath: '/project',
      mrId: 'mr-1',
      reviewData: { ...reviewData, threadsOpened: 3, threadsClosed: 1 },
    });

    expect(result?.openThreads).toBe(3);
    expect(result?.totalThreads).toBe(3);
  });

  it('should record followup type separately', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({ id: 'mr-1' });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({
      projectPath: '/project',
      mrId: 'mr-1',
      reviewData: { ...reviewData, type: 'followup' },
    });

    expect(result?.totalFollowups).toBe(1);
    expect(result?.totalReviews).toBe(0);
  });

  it('should set latestScore to the most recent review score', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({
      id: 'mr-1',
      reviews: [
        { type: 'review', timestamp: '2024-01-01T00:00:00Z', durationMs: 1000, score: 6, blocking: 0, warnings: 0, suggestions: 0, threadsClosed: 0, threadsOpened: 0, diffStats: null },
      ],
      totalReviews: 1,
      latestScore: 6,
    });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({
      projectPath: '/project',
      mrId: 'mr-1',
      reviewData: { ...reviewData, score: 10 },
    });

    expect(result?.latestScore).toBe(10);
  });

  it('should update latestScore from followup', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({
      id: 'mr-1',
      reviews: [
        { type: 'review', timestamp: '2024-01-01T00:00:00Z', durationMs: 1000, score: 5, blocking: 1, warnings: 0, suggestions: 0, threadsClosed: 0, threadsOpened: 1, diffStats: null },
      ],
      totalReviews: 1,
      latestScore: 5,
      openThreads: 1,
      totalThreads: 1,
    });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({
      projectPath: '/project',
      mrId: 'mr-1',
      reviewData: {
        type: 'followup',
        durationMs: 30000,
        score: 8,
        blocking: 0,
        warnings: 0,
        suggestions: 0,
        threadsClosed: 1,
      },
    });

    expect(result?.latestScore).toBe(8);
  });

  it('should record diffStats in review event when provided', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({ id: 'mr-1' });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const diffStats = DiffStatsFactory.create({ commitsCount: 5, additions: 200, deletions: 50 });
    const result = useCase.execute({
      projectPath: '/project',
      mrId: 'mr-1',
      reviewData: { ...reviewData, diffStats },
    });

    expect(result).not.toBeNull();
    expect(result?.reviews).toHaveLength(1);
    expect(result?.reviews[0].diffStats).toEqual({
      commitsCount: 5,
      additions: 200,
      deletions: 50,
    });
  });

  it('should set diffStats to null when not provided', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const mr = TrackedMrFactory.create({ id: 'mr-1' });
    gateway.create('/project', mr);
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({ projectPath: '/project', mrId: 'mr-1', reviewData });

    expect(result).not.toBeNull();
    expect(result?.reviews[0].diffStats).toBeNull();
  });

  it('should return null for unknown MR', () => {
    const gateway = new InMemoryReviewRequestTrackingGateway();
    const useCase = new RecordReviewCompletionUseCase(gateway);

    const result = useCase.execute({ projectPath: '/project', mrId: 'unknown-mr', reviewData });

    expect(result).toBeNull();
  });
});
