import { Feature, TestCase, TDDSession, TDDPhaseTransition } from './types.js';

export class TDDEnforcer {
  private sessions: Map<string, TDDSession> = new Map();

  startTDDSession(feature: Feature): TDDSession {
    if (feature.testCases.length === 0) {
      throw new Error(
        '🚫 TDD Violation: Cannot start development without tests!\n' +
        '📝 Please write at least one failing test before implementation.\n' +
        'Use the "write_test" tool to create your first test.'
      );
    }

    const failingTests = feature.testCases.filter(tc => tc.status !== 'passing');
    if (failingTests.length === 0) {
      throw new Error(
        '🚫 TDD Violation: All tests are already passing!\n' +
        '🔴 TDD requires starting with a failing test (RED phase).\n' +
        'Write a new test for the next behavior you want to implement.'
      );
    }

    const session: TDDSession = {
      id: this.generateId(),
      feature,
      currentPhase: 'red',
      history: [{
        from: 'red',
        to: 'red',
        timestamp: new Date(),
        message: `Started TDD session with ${failingTests.length} failing test(s)`,
      }],
      startedAt: new Date(),
    };

    this.sessions.set(session.id, session);
    return session;
  }

  canImplementCode(sessionId: string): { allowed: boolean; message: string } {
    const session = this.sessions.get(sessionId);
    
    if (!session) {
      return {
        allowed: false,
        message: '🚫 No active TDD session. Use "start_tdd_session" first.',
      };
    }

    if (session.currentPhase !== 'red') {
      return {
        allowed: false,
        message: `🚫 You're in the ${session.currentPhase.toUpperCase()} phase. You can only write implementation code in the RED phase.`,
      };
    }

    const failingTests = session.feature.testCases.filter(tc => tc.status === 'failing');
    if (failingTests.length === 0) {
      return {
        allowed: false,
        message: '🚫 No failing tests found. Write a failing test first!',
      };
    }

    return {
      allowed: true,
      message: `✅ You have ${failingTests.length} failing test(s). You may now implement code to make them pass.`,
    };
  }

  transitionToGreen(sessionId: string, passingTests: string[]): void {
    const session = this.sessions.get(sessionId);
    if (!session) {
      throw new Error('No active TDD session');
    }

    if (session.currentPhase !== 'red') {
      throw new Error(`Cannot transition to GREEN from ${session.currentPhase} phase`);
    }

    session.currentPhase = 'green';
    session.history.push({
      from: 'red',
      to: 'green',
      timestamp: new Date(),
      message: `Made ${passingTests.length} test(s) pass`,
    });
  }

  canRefactor(sessionId: string): { allowed: boolean; message: string } {
    const session = this.sessions.get(sessionId);
    
    if (!session) {
      return {
        allowed: false,
        message: '🚫 No active TDD session.',
      };
    }

    if (session.currentPhase !== 'green') {
      return {
        allowed: false,
        message: `🚫 You can only refactor in the GREEN phase. Current phase: ${session.currentPhase.toUpperCase()}`,
      };
    }

    const allTestsPassing = session.feature.testCases.every(tc => tc.status === 'passing');
    if (!allTestsPassing) {
      return {
        allowed: false,
        message: '🚫 Not all tests are passing. Fix failing tests before refactoring.',
      };
    }

    return {
      allowed: true,
      message: '✅ All tests passing. You may now refactor the code.',
    };
  }

  completeRefactoring(sessionId: string): void {
    const session = this.sessions.get(sessionId);
    if (!session) {
      throw new Error('No active TDD session');
    }

    if (session.currentPhase !== 'green') {
      throw new Error(`Cannot complete refactoring from ${session.currentPhase} phase`);
    }

    session.currentPhase = 'refactor';
    session.history.push({
      from: 'green',
      to: 'refactor',
      timestamp: new Date(),
      message: 'Completed refactoring while maintaining all tests passing',
    });
  }

  startNewCycle(sessionId: string): void {
    const session = this.sessions.get(sessionId);
    if (!session) {
      throw new Error('No active TDD session');
    }

    session.currentPhase = 'red';
    session.history.push({
      from: 'refactor',
      to: 'red',
      timestamp: new Date(),
      message: 'Started new TDD cycle',
    });
  }

  getSessionReport(sessionId: string): string {
    const session = this.sessions.get(sessionId);
    if (!session) {
      return '❌ No active TDD session found';
    }

    const duration = this.formatDuration(session.startedAt, session.completedAt || new Date());
    const cycleCount = session.history.filter(h => h.from === 'refactor' && h.to === 'red').length + 1;

    return `
🔄 TDD Session Report
━━━━━━━━━━━━━━━━━━━━
📋 Feature: ${session.feature.name}
⏱️  Duration: ${duration}
🔁 Cycles Completed: ${cycleCount}
📊 Current Phase: ${session.currentPhase.toUpperCase()}
✅ Tests Passing: ${session.feature.testCases.filter(tc => tc.status === 'passing').length}/${session.feature.testCases.length}

📜 History:
${session.history.map(h => `  • ${h.message} (${h.timestamp.toLocaleTimeString()})`).join('\n')}
`;
  }

  private generateId(): string {
    return Date.now().toString(36) + Math.random().toString(36).substr(2);
  }

  private formatDuration(start: Date, end: Date): string {
    const ms = end.getTime() - start.getTime();
    const minutes = Math.floor(ms / 60000);
    const seconds = Math.floor((ms % 60000) / 1000);
    return `${minutes}m ${seconds}s`;
  }
}