import { describe, it, expect } from 'vitest';
import type {
  ADR,
  ADRStatus,
  ADRTemplate,
  Option,
  ProsCons,
  StatusChange,
  CreateADROptions,
  UpdateADROptions,
  SearchADROptions,
  ADRMetrics,
  ADRRelationship
} from '../types.js';

describe('ADR Types', () => {
  describe('ADR Interface', () => {
    it('should have required fields', () => {
      const adr: ADR = {
        id: 'ADR-0001',
        title: 'Use React for Frontend Framework',
        status: 'accepted',
        date: new Date('2024-01-15'),
        deciders: ['John Doe', 'Jane Smith'],
        template: 'nygard',
        context: 'We need to choose a frontend framework',
        decision: 'We will use React',
        consequences: 'Team needs React training',
        createdAt: new Date('2024-01-15'),
        updatedAt: new Date('2024-01-15'),
        statusHistory: []
      };

      expect(adr.id).toMatch(/^ADR-\d{4}$/);
      expect(adr.status).toBe('accepted');
      expect(adr.template).toBe('nygard');
    });

    it('should support optional fields', () => {
      const adr: ADR = {
        id: 'ADR-0002',
        title: 'Adopt Microservices Architecture',
        status: 'proposed',
        date: new Date(),
        deciders: ['Architecture Team'],
        template: 'madr',
        context: 'System needs to scale',
        decision: 'Split into microservices',
        consequences: 'Increased complexity',
        decisionDrivers: ['Scalability', 'Team autonomy'],
        consideredOptions: [
          {
            title: 'Monolith',
            description: 'Keep current architecture',
            pros: ['Simple', 'Fast development'],
            cons: ['Hard to scale', 'Team bottlenecks']
          },
          {
            title: 'Microservices',
            description: 'Service-oriented architecture',
            pros: ['Scalable', 'Independent deployment'],
            cons: ['Complex', 'Network overhead']
          }
        ],
        prosAndCons: [
          {
            option: 'Microservices',
            pros: ['Better scalability'],
            cons: ['Operational complexity']
          }
        ],
        supersedes: ['ADR-0001'],
        relatedTo: ['ADR-0003'],
        tags: ['architecture', 'backend'],
        createdAt: new Date(),
        updatedAt: new Date(),
        statusHistory: []
      };

      expect(adr.decisionDrivers).toHaveLength(2);
      expect(adr.consideredOptions).toHaveLength(2);
      expect(adr.tags).toContain('architecture');
    });
  });

  describe('ADRStatus Type', () => {
    it('should only allow valid status values', () => {
      const validStatuses: ADRStatus[] = [
        'proposed',
        'accepted', 
        'rejected',
        'deprecated',
        'superseded'
      ];

      validStatuses.forEach(status => {
        const adr = { status } as { status: ADRStatus };
        expect(adr.status).toBe(status);
      });
    });
  });

  describe('ADRTemplate Type', () => {
    it('should support all template types', () => {
      const templates: ADRTemplate[] = ['nygard', 'madr', 'y-statement'];
      
      templates.forEach(template => {
        const adr = { template } as { template: ADRTemplate };
        expect(adr.template).toBe(template);
      });
    });
  });

  describe('Option Interface', () => {
    it('should have required fields', () => {
      const option: Option = {
        title: 'Option 1',
        description: 'Description of option',
        pros: ['Pro 1', 'Pro 2'],
        cons: ['Con 1', 'Con 2']
      };

      expect(option.title).toBeDefined();
      expect(option.pros).toHaveLength(2);
      expect(option.cons).toHaveLength(2);
    });
  });

  describe('StatusChange Interface', () => {
    it('should track status history', () => {
      const change: StatusChange = {
        from: 'proposed',
        to: 'accepted',
        date: new Date('2024-01-20'),
        changedBy: 'John Doe',
        reason: 'Approved by architecture board'
      };

      expect(change.from).toBe('proposed');
      expect(change.to).toBe('accepted');
      expect(change.reason).toBeDefined();
    });
  });

  describe('CreateADROptions Interface', () => {
    it('should have required fields for creation', () => {
      const options: CreateADROptions = {
        title: 'Use PostgreSQL for Database',
        template: 'nygard',
        deciders: ['DBA Team'],
        context: 'Need to choose a database',
        decision: 'Use PostgreSQL',
        consequences: 'Need PostgreSQL expertise'
      };

      expect(options.title).toBeDefined();
      expect(options.template).toBe('nygard');
      expect(options.deciders).toHaveLength(1);
    });

    it('should support MADR-specific fields', () => {
      const options: CreateADROptions = {
        title: 'Choose API Protocol',
        template: 'madr',
        deciders: ['API Team'],
        context: 'Need to define API protocol',
        decision: 'Use GraphQL',
        consequences: 'Learning curve for team',
        decisionDrivers: ['Flexibility', 'Performance'],
        consideredOptions: [
          {
            title: 'REST',
            description: 'RESTful API',
            pros: ['Simple', 'Well-known'],
            cons: ['Over-fetching', 'Multiple requests']
          },
          {
            title: 'GraphQL',
            description: 'Query language for APIs',
            pros: ['Flexible', 'Single request'],
            cons: ['Complexity', 'Learning curve']
          }
        ]
      };

      expect(options.decisionDrivers).toHaveLength(2);
      expect(options.consideredOptions).toHaveLength(2);
    });
  });

  describe('UpdateADROptions Interface', () => {
    it('should allow partial updates', () => {
      const update: UpdateADROptions = {
        status: 'deprecated',
        supersededBy: 'ADR-0010',
        consequences: 'Updated consequences'
      };

      expect(update.status).toBe('deprecated');
      expect(update.supersededBy).toBe('ADR-0010');
    });
  });

  describe('SearchADROptions Interface', () => {
    it('should support various search criteria', () => {
      const search: SearchADROptions = {
        query: 'database',
        status: ['accepted', 'proposed'],
        tags: ['backend', 'architecture'],
        dateRange: {
          from: new Date('2024-01-01'),
          to: new Date('2024-12-31')
        },
        template: 'madr'
      };

      expect(search.query).toBe('database');
      expect(search.status).toContain('accepted');
      expect(search.tags).toContain('backend');
      expect(search.dateRange?.from).toBeDefined();
    });
  });

  describe('ADRMetrics Interface', () => {
    it('should track ADR statistics', () => {
      const metrics: ADRMetrics = {
        total: 50,
        byStatus: {
          proposed: 5,
          accepted: 35,
          rejected: 3,
          deprecated: 5,
          superseded: 2
        },
        byTemplate: {
          nygard: 30,
          madr: 15,
          'y-statement': 5
        },
        averageDecisionTime: 7.5,
        mostActiveDeciders: [
          { name: 'John Doe', count: 20 },
          { name: 'Jane Smith', count: 15 }
        ],
        recentActivity: [
          {
            adrId: 'ADR-0050',
            action: 'created',
            date: new Date(),
            actor: 'John Doe'
          }
        ]
      };

      expect(metrics.total).toBe(50);
      expect(metrics.byStatus.accepted).toBe(35);
      expect(metrics.mostActiveDeciders).toHaveLength(2);
    });
  });

  describe('ADRRelationship Interface', () => {
    it('should define relationships between ADRs', () => {
      const relationship: ADRRelationship = {
        type: 'supersedes',
        from: 'ADR-0010',
        to: 'ADR-0005',
        description: 'Replaces old authentication approach'
      };

      expect(relationship.type).toBe('supersedes');
      expect(relationship.from).toMatch(/^ADR-\d{4}$/);
      expect(relationship.to).toMatch(/^ADR-\d{4}$/);
    });

    it('should support all relationship types', () => {
      const types: ADRRelationship['type'][] = [
        'supersedes',
        'superseded-by',
        'related-to',
        'depends-on',
        'conflicts-with'
      ];

      types.forEach(type => {
        const rel: ADRRelationship = {
          type,
          from: 'ADR-0001',
          to: 'ADR-0002'
        };
        expect(rel.type).toBe(type);
      });
    });
  });
});