import { describe, it, expect, beforeEach } from 'vitest';
import { TDDEnforcer } from '../tdd-enforcer.js';
import { Feature, TestCase } from '../types.js';

describe('TDDEnforcer', () => {
  let enforcer: TDDEnforcer;
  let testFeature: Feature;

  beforeEach(() => {
    enforcer = new TDDEnforcer();
    testFeature = {
      id: 'feature1',
      name: 'User Authentication',
      description: 'Implement user login functionality',
      testCases: [],
      implementationStatus: 'not-started',
      testCoverage: 0,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
  });

  describe('startTDDSession', () => {
    it('should throw error when no tests exist', () => {
      expect(() => enforcer.startTDDSession(testFeature)).toThrow(
        'TDD Violation: Cannot start development without tests!'
      );
    });

    it('should throw error when all tests are passing', () => {
      testFeature.testCases = [
        {
          id: 'test1',
          name: 'should authenticate valid user',
          description: 'Test login with valid credentials',
          type: 'unit',
          status: 'passing',
          expectedBehavior: 'User is authenticated',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];

      expect(() => enforcer.startTDDSession(testFeature)).toThrow(
        'TDD Violation: All tests are already passing!'
      );
    });

    it('should start session when failing tests exist', () => {
      testFeature.testCases = [
        {
          id: 'test1',
          name: 'should authenticate valid user',
          description: 'Test login with valid credentials',
          type: 'unit',
          status: 'failing',
          expectedBehavior: 'User is authenticated',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];

      const session = enforcer.startTDDSession(testFeature);
      expect(session).toBeDefined();
      expect(session.currentPhase).toBe('red');
      expect(session.feature).toBe(testFeature);
    });
  });

  describe('canImplementCode', () => {
    it('should not allow implementation without active session', () => {
      const result = enforcer.canImplementCode('invalid-session');
      expect(result.allowed).toBe(false);
      expect(result.message).toContain('No active TDD session');
    });

    it('should allow implementation in RED phase with failing tests', () => {
      testFeature.testCases = [
        {
          id: 'test1',
          name: 'test',
          description: 'test',
          type: 'unit',
          status: 'failing',
          expectedBehavior: 'expected',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];
      const session = enforcer.startTDDSession(testFeature);
      
      const result = enforcer.canImplementCode(session.id);
      expect(result.allowed).toBe(true);
      expect(result.message).toContain('You may now implement code');
    });

    it('should not allow implementation in GREEN phase', () => {
      testFeature.testCases = [
        {
          id: 'test1',
          name: 'test',
          description: 'test',
          type: 'unit',
          status: 'failing',
          expectedBehavior: 'expected',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];
      const session = enforcer.startTDDSession(testFeature);
      
      // Simulate transition to GREEN
      testFeature.testCases[0].status = 'passing';
      enforcer.transitionToGreen(session.id, ['test1']);
      
      const result = enforcer.canImplementCode(session.id);
      expect(result.allowed).toBe(false);
      expect(result.message).toContain('GREEN phase');
    });
  });

  describe('canRefactor', () => {
    let sessionId: string;

    beforeEach(() => {
      testFeature.testCases = [
        {
          id: 'test1',
          name: 'test',
          description: 'test',
          type: 'unit',
          status: 'failing',
          expectedBehavior: 'expected',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];
      const session = enforcer.startTDDSession(testFeature);
      sessionId = session.id;
    });

    it('should not allow refactoring in RED phase', () => {
      const result = enforcer.canRefactor(sessionId);
      expect(result.allowed).toBe(false);
      expect(result.message).toContain('only refactor in the GREEN phase');
    });

    it('should allow refactoring in GREEN phase with all tests passing', () => {
      // Transition to GREEN with all tests passing
      testFeature.testCases[0].status = 'passing';
      enforcer.transitionToGreen(sessionId, ['test1']);
      
      const result = enforcer.canRefactor(sessionId);
      expect(result.allowed).toBe(true);
      expect(result.message).toContain('You may now refactor');
    });

    it('should not allow refactoring if tests are failing', () => {
      // Transition to GREEN but keep test failing
      enforcer.transitionToGreen(sessionId, []);
      
      const result = enforcer.canRefactor(sessionId);
      expect(result.allowed).toBe(false);
      expect(result.message).toContain('Not all tests are passing');
    });
  });

  describe('getSessionReport', () => {
    it('should return error message for invalid session', () => {
      const report = enforcer.getSessionReport('invalid-id');
      expect(report).toContain('No active TDD session found');
    });

    it('should return detailed report for active session', () => {
      testFeature.testCases = [
        {
          id: 'test1',
          name: 'test',
          description: 'test',
          type: 'unit',
          status: 'failing',
          expectedBehavior: 'expected',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];
      const session = enforcer.startTDDSession(testFeature);
      
      const report = enforcer.getSessionReport(session.id);
      expect(report).toContain('TDD Session Report');
      expect(report).toContain('User Authentication');
      expect(report).toContain('Current Phase: RED');
      expect(report).toContain('Tests Passing: 0/1');
    });
  });

  describe('TDD cycle transitions', () => {
    let sessionId: string;

    beforeEach(() => {
      testFeature.testCases = [
        {
          id: 'test1',
          name: 'test',
          description: 'test',
          type: 'unit',
          status: 'failing',
          expectedBehavior: 'expected',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];
      const session = enforcer.startTDDSession(testFeature);
      sessionId = session.id;
    });

    it('should complete full TDD cycle: RED -> GREEN -> REFACTOR -> RED', () => {
      // RED phase (initial)
      expect(enforcer.canImplementCode(sessionId).allowed).toBe(true);
      
      // Transition to GREEN
      testFeature.testCases[0].status = 'passing';
      enforcer.transitionToGreen(sessionId, ['test1']);
      expect(enforcer.canRefactor(sessionId).allowed).toBe(true);
      
      // Complete refactoring
      enforcer.completeRefactoring(sessionId);
      
      // Start new cycle
      enforcer.startNewCycle(sessionId);
      const report = enforcer.getSessionReport(sessionId);
      expect(report).toContain('Current Phase: RED');
      expect(report).toContain('Cycles Completed: 2');
    });
  });
});