/**
 * Comprehensive Test Runner for Evidence DSL
 * 
 * Orchestrates all test suites in a structural linguistic approach,
 * from basic primitives to complex integration scenarios.
 */

import { runStructuralLinguisticTests } from './StructuralLinguisticTests.js';
import { runExpressionTests } from './ExpressionTests.js';
import { runDefinitionTests } from './DefinitionTests.js';
import { runFactTests } from './FactTests.js';
import { runEvidenceTests } from './EvidenceTests.js';
import { runMeasureTests } from './MeasureTests.js';
import { runIntegrationTests } from './IntegrationTests.js';

export class TestRunner {
  constructor() {
    this.arbiter = null;
    this.testSuites = [];
    this.results = {
      total: 0,
      passed: 0,
      failed: 0,
      success: false,
      suites: []
    };
  }

  setup(arbiter) {
    this.arbiter = arbiter;
    this.testSuites = [
      {
        name: 'Structural Linguistic Tests',
        description: 'Comprehensive tests from basic primitives to complex features',
        runner: runStructuralLinguisticTests,
        level: 'comprehensive'
      },
      {
        name: 'Expression Tests',
        description: 'Expression parsing, operator precedence, and complex expressions',
        runner: runExpressionTests,
        level: 'focused'
      },
      {
        name: 'Definition Tests',
        description: 'Type definitions, fields, behaviors, and caching',
        runner: runDefinitionTests,
        level: 'focused'
      },
      {
        name: 'Fact Tests',
        description: 'Fact declarations, properties, and caching',
        runner: runFactTests,
        level: 'focused'
      },
      {
        name: 'Evidence Tests',
        description: 'Evidence rules, defeasible logic, and pattern matching',
        runner: runEvidenceTests,
        level: 'focused'
      },
      {
        name: 'Measure Tests',
        description: 'Measure definitions, aggregation, and fusion',
        runner: runMeasureTests,
        level: 'focused'
      },
      {
        name: 'Integration Tests',
        description: 'Complex multi-feature integration scenarios',
        runner: runIntegrationTests,
        level: 'integration'
      }
    ];
  }

  /**
   * Run all test suites
   * @returns {Object} Comprehensive test results
   */
  runAllTests() {
    console.log('='.repeat(80));
    console.log('EVIDENCE DSL COMPREHENSIVE TEST SUITE');
    console.log('='.repeat(80));
    console.log('Structural Linguistic Approach: Testing from primitives to integration\n');

    const startTime = Date.now();

    for (const suite of this.testSuites) {
      console.log(`\n${'='.repeat(60)}`);
      console.log(`Running: ${suite.name}`);
      console.log(`Level: ${suite.level.toUpperCase()}`);
      console.log(`Description: ${suite.description}`);
      console.log(`${'='.repeat(60)}`);

      try {
        const suiteStartTime = Date.now();
        const suiteResults = suite.runner(this.arbiter);
        const suiteEndTime = Date.now();
        const suiteDuration = suiteEndTime - suiteStartTime;

        this.results.suites.push({
          name: suite.name,
          level: suite.level,
          duration: suiteDuration,
          results: suiteResults
        });

        this.results.total += suiteResults.total;
        this.results.passed += suiteResults.passed;
        this.results.failed += suiteResults.failed;

        console.log(`\n${suite.name} completed in ${suiteDuration}ms`);
        console.log(`Results: ${suiteResults.passed}/${suiteResults.total} passed, ${suiteResults.failed} failed`);

        if (suiteResults.success) {
          console.log(`✓ ${suite.name} PASSED`);
        } else {
          console.log(`✗ ${suite.name} FAILED`);
        }

      } catch (error) {
        console.error(`\n✗ ${suite.name} ERROR: ${error.message}`);
        this.results.suites.push({
          name: suite.name,
          level: suite.level,
          duration: 0,
          results: {
            total: 0,
            passed: 0,
            failed: 1,
            success: false,
            error: error.message
          }
        });
        this.results.failed += 1;
      }
    }

    const endTime = Date.now();
    const totalDuration = endTime - startTime;

    this.results.success = this.results.failed === 0;

    this.printSummary(totalDuration);
    this.printDetailedResults();

    return this.results;
  }

  /**
   * Run specific test suites
   * @param {string[]} suiteNames - Names of test suites to run
   * @returns {Object} Test results for specified suites
   */
  runSpecificTests(suiteNames) {
    console.log('='.repeat(80));
    console.log('EVIDENCE DSL SELECTIVE TEST SUITE');
    console.log('='.repeat(80));
    console.log(`Running: ${suiteNames.join(', ')}\n`);

    const startTime = Date.now();
    const selectedSuites = this.testSuites.filter(suite => suiteNames.includes(suite.name));

    for (const suite of selectedSuites) {
      console.log(`\n${'='.repeat(60)}`);
      console.log(`Running: ${suite.name}`);
      console.log(`${'='.repeat(60)}`);

      try {
        const suiteStartTime = Date.now();
        const suiteResults = suite.runner(this.arbiter);
        const suiteEndTime = Date.now();
        const suiteDuration = suiteEndTime - suiteStartTime;

        this.results.suites.push({
          name: suite.name,
          level: suite.level,
          duration: suiteDuration,
          results: suiteResults
        });

        this.results.total += suiteResults.total;
        this.results.passed += suiteResults.passed;
        this.results.failed += suiteResults.failed;

        console.log(`\n${suite.name} completed in ${suiteDuration}ms`);
        console.log(`Results: ${suiteResults.passed}/${suiteResults.total} passed, ${suiteResults.failed} failed`);

      } catch (error) {
        console.error(`\n✗ ${suite.name} ERROR: ${error.message}`);
        this.results.failed += 1;
      }
    }

    const endTime = Date.now();
    const totalDuration = endTime - startTime;

    this.results.success = this.results.failed === 0;
    this.printSummary(totalDuration);

    return this.results;
  }

  /**
   * Run tests by level
   * @param {string} level - Test level to run ('comprehensive', 'focused', 'integration')
   * @returns {Object} Test results for specified level
   */
  runTestsByLevel(level) {
    const levelSuites = this.testSuites.filter(suite => suite.level === level);
    const suiteNames = levelSuites.map(suite => suite.name);
    return this.runSpecificTests(suiteNames);
  }

  /**
   * Print test summary
   * @param {number} totalDuration - Total test duration in milliseconds
   */
  printSummary(totalDuration) {
    console.log('\n' + '='.repeat(80));
    console.log('TEST SUMMARY');
    console.log('='.repeat(80));
    console.log(`Total Tests: ${this.results.total}`);
    console.log(`Passed: ${this.results.passed}`);
    console.log(`Failed: ${this.results.failed}`);
    console.log(`Success Rate: ${((this.results.passed / this.results.total) * 100).toFixed(2)}%`);
    console.log(`Total Duration: ${totalDuration}ms`);
    console.log(`Status: ${this.results.success ? '✓ ALL TESTS PASSED' : '✗ SOME TESTS FAILED'}`);
    console.log('='.repeat(80));
  }

  /**
   * Print detailed results for each test suite
   */
  printDetailedResults() {
    console.log('\n' + '='.repeat(80));
    console.log('DETAILED RESULTS');
    console.log('='.repeat(80));

    this.results.suites.forEach(suite => {
      console.log(`\n${suite.name} (${suite.level}):`);
      console.log(`  Duration: ${suite.duration}ms`);
      console.log(`  Total: ${suite.results.total}`);
      console.log(`  Passed: ${suite.results.passed}`);
      console.log(`  Failed: ${suite.results.failed}`);
      console.log(`  Success: ${suite.results.success ? '✓' : '✗'}`);

      if (suite.results.error) {
        console.log(`  Error: ${suite.results.error}`);
      }

      if (suite.results.results && suite.results.results.length > 0) {
        console.log('  Individual Results:');
        suite.results.results.forEach(result => {
          const status = result.status === 'PASSED' ? '✓' : '✗';
          console.log(`    ${status} ${result.test}`);
          if (result.error) {
            console.log(`      Error: ${result.error}`);
          }
        });
      }
    });
  }

  /**
   * Get test coverage report
   * @returns {Object} Coverage report
   */
  getCoverageReport() {
    const coverage = {
      lexical: {
        identifiers: 'tested',
        literals: 'tested',
        keywords: 'tested',
        whitespace: 'tested'
      },
      expressions: {
        arithmetic: 'tested',
        logical: 'tested',
        comparison: 'tested',
        temporal: 'tested',
        unary: 'tested',
        attributeAccess: 'tested',
        functionCalls: 'tested'
      },
      types: {
        definitions: 'tested',
        fields: 'tested',
        behaviors: 'tested',
        caching: 'tested',
        arrays: 'tested'
      },
      facts: {
        declarations: 'tested',
        properties: 'tested',
        caching: 'tested',
        limits: 'tested',
        parameters: 'tested'
      },
      evidence: {
        basic: 'tested',
        defeasibleLogic: 'tested',
        patternMatching: 'tested',
        fusion: 'tested',
        complex: 'tested'
      },
      measures: {
        basic: 'tested',
        aggregation: 'tested',
        fusion: 'tested',
        returnTypes: 'tested',
        complex: 'tested'
      },
      integration: {
        completeSystems: 'tested',
        multiDomain: 'tested',
        hierarchical: 'tested',
        similarity: 'tested',
        temporal: 'tested',
        behaviors: 'tested',
        performance: 'tested'
      }
    };

    return coverage;
  }

  /**
   * Get language feature coverage
   * @returns {Object} Feature coverage report
   */
  getFeatureCoverage() {
    return {
      languagePrimitives: {
        identifiers: '✓',
        literals: '✓',
        keywords: '✓',
        operators: '✓',
        expressions: '✓'
      },
      typeSystem: {
        definitions: '✓',
        fields: '✓',
        behaviors: '✓',
        caching: '✓',
        arrays: '✓'
      },
      factSystem: {
        declarations: '✓',
        properties: '✓',
        caching: '✓',
        limits: '✓',
        parameters: '✓'
      },
      evidenceSystem: {
        rules: '✓',
        defeasibleLogic: '✓',
        patternMatching: '✓',
        fusion: '✓',
        complex: '✓'
      },
      measureSystem: {
        definitions: '✓',
        aggregation: '✓',
        fusion: '✓',
        returnTypes: '✓',
        complex: '✓'
      },
      integration: {
        multiFeature: '✓',
        realWorld: '✓',
        performance: '✓',
        scalability: '✓'
      }
    };
  }
}

/**
 * Run all tests
 * @param {Object} arbiter - Arbiter instance for testing
 * @returns {Object} Comprehensive test results
 */
export function runAllTests(arbiter) {
  const runner = new TestRunner();
  runner.setup(arbiter);
  return runner.runAllTests();
}

/**
 * Run specific test suites
 * @param {Object} arbiter - Arbiter instance for testing
 * @param {string[]} suiteNames - Names of test suites to run
 * @returns {Object} Test results for specified suites
 */
export function runSpecificTests(arbiter, suiteNames) {
  const runner = new TestRunner();
  runner.setup(arbiter);
  return runner.runSpecificTests(suiteNames);
}

/**
 * Run tests by level
 * @param {Object} arbiter - Arbiter instance for testing
 * @param {string} level - Test level to run
 * @returns {Object} Test results for specified level
 */
export function runTestsByLevel(arbiter, level) {
  const runner = new TestRunner();
  runner.setup(arbiter);
  return runner.runTestsByLevel(level);
}
