/**
 * Type Definition Tests
 * 
 * Tests the type definition system of the Evidence DSL,
 * including fields, behaviors, caching, and complex type structures.
 */

import { DSLCompiler } from '../DSLCompiler.js';

export class DefinitionTests {
  constructor() {
    this.arbiter = null;
    this.compiler = null;
    this.testResults = [];
  }

  setup(arbiter) {
    this.arbiter = arbiter;
    this.compiler = new DSLCompiler(arbiter);
  }

  runAllTests() {
    console.log('=== Type Definition Tests ===\n');

    this.testBasicDefinitions();
    this.testFieldTypes();
    this.testArrayTypes();
    this.testBehaviors();
    this.testCaching();
    this.testComplexDefinitions();
    this.testDefinitionErrors();

    return this.getTestResults();
  }

  testBasicDefinitions() {
    console.log('Testing Basic Definitions...');
    
    const testCases = [
      {
        input: `definition User { role: string }`,
        description: 'Simple definition with one field'
      },
      {
        input: `definition User { 
          role: string
          isActive: boolean
        }`,
        description: 'Definition with multiple fields'
      },
      {
        input: `definition Group { 
          name: string
          description: string
          created: timestamp
        }`,
        description: 'Definition with different field types'
      }
    ];

    testCases.forEach(({ input, description }) => {
      try {
        const result = this.compiler.compile(input, `test-basic-def-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        this.assert(result.program.definitions.length > 0, 'Should have definitions');
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Basic definition test: ${description}`, error);
      }
    });
  }

  testFieldTypes() {
    console.log('Testing Field Types...');
    
    const testCases = [
      { type: 'string', description: 'String field type' },
      { type: 'number', description: 'Number field type' },
      { type: 'boolean', description: 'Boolean field type' },
      { type: 'timestamp', description: 'Timestamp field type' },
      { type: 'User', description: 'Custom type field' },
      { type: 'Permission', description: 'Another custom type field' }
    ];

    testCases.forEach(({ type, description }) => {
      try {
        const dsl = `definition Test { field: ${type} }`;
        const result = this.compiler.compile(dsl, `test-field-type-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Field type test: ${description}`, error);
      }
    });
  }

  testArrayTypes() {
    console.log('Testing Array Types...');
    
    const testCases = [
      { type: 'string[]', description: 'String array' },
      { type: 'number[]', description: 'Number array' },
      { type: 'boolean[]', description: 'Boolean array' },
      { type: 'Permission[]', description: 'Custom type array' },
      { type: 'User[]', description: 'User array' }
    ];

    testCases.forEach(({ type, description }) => {
      try {
        const dsl = `definition Test { items: ${type} }`;
        const result = this.compiler.compile(dsl, `test-array-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Array type test: ${description}`, error);
      }
    });
  }

  testBehaviors() {
    console.log('Testing Behaviors...');
    
    const testCases = [
      {
        input: `definition User { 
          balance: number BEHAVES { decaying down hourly } 
        }`,
        description: 'Decay behavior - down hourly'
      },
      {
        input: `definition User { 
          reputation: number BEHAVES { decaying up daily } 
        }`,
        description: 'Decay behavior - up daily'
      },
      {
        input: `definition User { 
          score: number BEHAVES { decaying neutral weekly } 
        }`,
        description: 'Decay behavior - neutral weekly'
      },
      {
        input: `definition User { 
          stability: number BEHAVES { decaying stable monthly } 
        }`,
        description: 'Decay behavior - stable monthly'
      },
      {
        input: `definition User { 
          confidence: number BEHAVES { blurring fixed } 
        }`,
        description: 'Blur behavior - fixed'
      },
      {
        input: `definition User { 
          accuracy: number BEHAVES { blurring adaptive } 
        }`,
        description: 'Blur behavior - adaptive'
      },
      {
        input: `definition User { 
          precision: number BEHAVES { blurring confidence confidence_90 } 
        }`,
        description: 'Blur behavior - confidence with level'
      },
      {
        input: `definition User { 
          session: string BEHAVES { ttl 1h } 
        }`,
        description: 'TTL behavior - hours'
      },
      {
        input: `definition User { 
          token: string BEHAVES { ttl 24h } 
        }`,
        description: 'TTL behavior - 24 hours'
      },
      {
        input: `definition User { 
          cache: string BEHAVES { ttl 7d } 
        }`,
        description: 'TTL behavior - days'
      }
    ];

    testCases.forEach(({ input, description }) => {
      try {
        const result = this.compiler.compile(input, `test-behavior-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Behavior test: ${description}`, error);
      }
    });
  }

  testCaching() {
    console.log('Testing Caching...');
    
    const testCases = [
      {
        input: `definition User { 
          role: string CACHE eager 
        }`,
        description: 'Eager caching'
      },
      {
        input: `definition User { 
          score: number CACHE lazy 
        }`,
        description: 'Lazy caching'
      },
      {
        input: `definition User { 
          balance: number BEHAVES { decaying down hourly } CACHE eager 
        }`,
        description: 'Behavior with eager caching'
      },
      {
        input: `definition User { 
          reputation: number BEHAVES { blurring adaptive } CACHE lazy 
        }`,
        description: 'Behavior with lazy caching'
      }
    ];

    testCases.forEach(({ input, description }) => {
      try {
        const result = this.compiler.compile(input, `test-cache-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Cache test: ${description}`, error);
      }
    });
  }

  testComplexDefinitions() {
    console.log('Testing Complex Definitions...');
    
    const testCases = [
      {
        input: `definition User {
          role: string
          isActive: boolean
          lastActive: timestamp BEHAVES {
            decaying down hourly
          } CACHE lazy
          isSuspended: boolean
          balance: number BEHAVES {
            decaying down hourly
          } CACHE eager
          score: number BEHAVES {
            blurring adaptive confidence_95
          } CACHE lazy
          session: string BEHAVES {
            ttl 24h
          } CACHE eager
        }`,
        description: 'Complex definition with multiple behaviors and caching'
      },
      {
        input: `definition Group {
          name: string
          permissions: Permission[]
          members: User[]
          created: timestamp BEHAVES {
            decaying stable monthly
          } CACHE lazy
          isPublic: boolean CACHE eager
        }`,
        description: 'Definition with arrays and mixed behaviors'
      },
      {
        input: `definition Document {
          level: string
          owner: User
          tags: string[]
          content: string BEHAVES {
            blurring fixed
          } CACHE lazy
          accessCount: number BEHAVES {
            decaying up daily
          } CACHE eager
          expiresAt: timestamp BEHAVES {
            ttl 30d
          } CACHE eager
        }`,
        description: 'Definition with all behavior types'
      }
    ];

    testCases.forEach(({ input, description }) => {
      try {
        const result = this.compiler.compile(input, `test-complex-def-${Date.now()}`);
        this.assert(result.success, `${description} should parse successfully`);
        this.assert(result.program.definitions.length > 0, 'Should have definitions');
        console.log(`  ✓ ${description}`);
      } catch (error) {
        this.fail(`Complex definition test: ${description}`, error);
      }
    });
  }

  testDefinitionErrors() {
    console.log('Testing Definition Error Handling...');
    
    const testCases = [
      {
        input: `definition User { role: string`,
        description: 'Missing closing brace should fail'
      },
      {
        input: `definition User { role: }`,
        description: 'Missing field type should fail'
      },
      {
        input: `definition User { : string }`,
        description: 'Missing field name should fail'
      },
      {
        input: `definition User { role: string BEHAVES { }`,
        description: 'Incomplete behavior should fail'
      },
      {
        input: `definition User { role: string CACHE }`,
        description: 'Incomplete cache directive should fail'
      },
      {
        input: `definition User { role: string BEHAVES { invalid } }`,
        description: 'Invalid behavior should fail'
      }
    ];

    testCases.forEach(({ input, description }) => {
      try {
        const result = this.compiler.compile(input, `test-def-error-${Date.now()}`);
        this.assert(!result.success, `${description} should fail to parse`);
        console.log(`  ✓ ${description} (correctly failed)`);
      } catch (error) {
        // Expected to fail
        console.log(`  ✓ ${description} (correctly failed)`);
      }
    });
  }

  assert(condition, message) {
    if (!condition) {
      throw new Error(`Assertion failed: ${message}`);
    }
  }

  fail(testName, error) {
    console.log(`  ✗ ${testName} failed: ${error.message}`);
    this.testResults.push({
      test: testName,
      status: 'FAILED',
      error: error.message
    });
  }

  getTestResults() {
    const passed = this.testResults.filter(r => r.status === 'PASSED').length;
    const failed = this.testResults.filter(r => r.status === 'FAILED').length;
    const total = this.testResults.length;

    return {
      total: total,
      passed: passed,
      failed: failed,
      success: failed === 0,
      results: this.testResults
    };
  }
}

export function runDefinitionTests(arbiter) {
  const test = new DefinitionTests();
  test.setup(arbiter);
  return test.runAllTests();
}
