/**
 * Tests for Enhanced Access Control Generator
 */

import { EnhancedAccessControlGenerator } from './enhanced-access-control-generator';
import type { GeneratorContext as _GeneratorContext } from '../types';
import { Workflow } from '../../types/workflow';

describe('EnhancedAccessControlGenerator', () => {
  let generator: EnhancedAccessControlGenerator;

  beforeEach(() => {
    generator = new EnhancedAccessControlGenerator();
  });

  it('should have correct metadata', () => {
    expect(generator.id).toBe('enhanced-access-control');
    expect(generator.name).toBe('Enhanced Access Control Generator');
    expect(generator.description).toContain('access control');
  });

  it('should return empty result when no access_control config', () => {
    const workflow: Workflow = {
      workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
      stack: { api: { type: 'backend', technology: 'typescript/express' } },
      stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
    };

    const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
    expect(result.files).toHaveLength(0);
  });

  describe('RBAC Model', () => {
    it('should generate RBAC service', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { api: { type: 'backend', technology: 'typescript/express' } },
        access_control: {
          model: 'rbac',
          roles: [
            {
              name: 'admin',
              permissions: [{ resource: 'users', actions: ['read', 'write', 'delete'] }],
            },
          ],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const rbacFile = result.files.find(f => f.path.includes('services/rbac.ts'));

      expect(rbacFile).toBeDefined();
      expect(rbacFile!.content).toContain('RBACService');
      expect(rbacFile!.content).toContain('can(');
      expect(rbacFile!.content).toContain('hasRole');
    });
  });

  describe('ABAC Model', () => {
    it('should generate ABAC service', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { api: { type: 'backend', technology: 'typescript/express' } },
        access_control: {
          model: 'abac',
          roles: [],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const abacFile = result.files.find(f => f.path.includes('services/abac.ts'));

      expect(abacFile).toBeDefined();
      expect(abacFile!.content).toContain('ABACService');
      expect(abacFile!.content).toContain('evaluateCondition');
      expect(abacFile!.content).toContain('evaluateConditions');
    });
  });

  describe('Hybrid Model', () => {
    it('should generate both RBAC and ABAC services for hybrid model', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { api: { type: 'backend', technology: 'typescript/express' } },
        access_control: {
          model: 'rbac_with_abac',
          roles: [
            {
              name: 'manager',
              permissions: [
                {
                  resource: 'documents',
                  actions: ['read', 'write'],
                  conditions: [{ field: 'user.department', operator: 'equals', value: 'HR' }],
                },
              ],
            },
          ],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });

      expect(result.files.find(f => f.path.includes('services/rbac.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('services/abac.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('services/authorization.ts'))).toBeDefined();
    });
  });

  describe('Backend Files', () => {
    it('should generate access control types', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { api: { type: 'backend', technology: 'typescript/express' } },
        access_control: {
          model: 'rbac',
          roles: [
            { name: 'user', permissions: [{ resource: 'posts', actions: ['read'] }] },
            { name: 'admin', permissions: [{ resource: 'posts', actions: ['read', 'write'] }] },
          ],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const typesFile = result.files.find(f => f.path.includes('types/access-control.ts'));

      expect(typesFile).toBeDefined();
      expect(typesFile!.content).toContain("type RoleName =");
      expect(typesFile!.content).toContain("'user'");
      expect(typesFile!.content).toContain("'admin'");
    });

    it('should generate roles configuration', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { api: { type: 'backend', technology: 'typescript/express' } },
        access_control: {
          model: 'rbac',
          roles: [
            {
              name: 'editor',
              permissions: [
                { resource: 'articles', actions: ['read', 'write'] },
                { resource: 'comments', actions: ['read'] },
              ],
            },
          ],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const rolesFile = result.files.find(f => f.path.includes('config/roles.ts'));

      expect(rolesFile).toBeDefined();
      expect(rolesFile!.content).toContain('editor');
      expect(rolesFile!.content).toContain('articles');
      expect(rolesFile!.content).toContain('getRoleByName');
    });

    it('should generate authorization middleware', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { api: { type: 'backend', technology: 'typescript/express' } },
        access_control: {
          model: 'rbac',
          roles: [{ name: 'user', permissions: [{ resource: 'profile', actions: ['read'] }] }],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const middlewareFile = result.files.find(f => f.path.includes('middleware/authorization.ts'));

      expect(middlewareFile).toBeDefined();
      expect(middlewareFile!.content).toContain('authorize(');
      expect(middlewareFile!.content).toContain('requireRole');
      expect(middlewareFile!.content).toContain('requireAllRoles');
    });

    it('should generate policy engine when policies defined', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { api: { type: 'backend', technology: 'typescript/express' } },
        access_control: {
          model: 'rbac',
          roles: [],
          policies: [
            {
              name: 'admin_full_access',
              resource: 'users',
              action: 'delete',
              rules: [{ role: 'admin' }],
            },
          ],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const policyFile = result.files.find(f => f.path.includes('services/policy-engine.ts'));

      expect(policyFile).toBeDefined();
      expect(policyFile!.content).toContain('PolicyEngine');
      expect(policyFile!.content).toContain('evaluatePolicy');
      expect(policyFile!.content).toContain('admin_full_access');
    });
  });

  describe('Frontend Files', () => {
    it('should generate permission hooks', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { web: { type: 'frontend', technology: 'react' } },
        access_control: {
          model: 'rbac',
          roles: [{ name: 'user', permissions: [{ resource: 'dashboard', actions: ['view'] }] }],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const hooksFile = result.files.find(f => f.path.includes('hooks/usePermissions.ts'));

      expect(hooksFile).toBeDefined();
      expect(hooksFile!.content).toContain('useCan');
      expect(hooksFile!.content).toContain('usePermissions');
      expect(hooksFile!.content).toContain('useRole');
    });

    it('should generate Can component', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { web: { type: 'frontend', technology: 'react' } },
        access_control: {
          model: 'rbac',
          roles: [{ name: 'user', permissions: [{ resource: 'posts', actions: ['create'] }] }],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const canFile = result.files.find(f => f.path.includes('components/Can.tsx'));

      expect(canFile).toBeDefined();
      expect(canFile!.content).toContain('Can:');
      expect(canFile!.content).toContain('Cannot:');
      expect(canFile!.content).toContain('perform');
      expect(canFile!.content).toContain('fallback');
    });

    it('should generate authorization provider', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: { web: { type: 'frontend', technology: 'react' } },
        access_control: {
          model: 'rbac',
          roles: [{ name: 'viewer', permissions: [{ resource: 'content', actions: ['read'] }] }],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });
      const providerFile = result.files.find(f => f.path.includes('providers/AuthorizationProvider.tsx'));

      expect(providerFile).toBeDefined();
      expect(providerFile!.content).toContain('AuthorizationProvider');
      expect(providerFile!.content).toContain('AuthorizationContext');
      expect(providerFile!.content).toContain('fetchPermissions');
    });
  });

  describe('Complete Schema', () => {
    it('should generate all files for complete access control schema', () => {
      const workflow: Workflow = {
        workflow: { id: 'test', version: '1.0.0', name: 'Test', description: 'Test' },
        stack: {
          web: { type: 'frontend', technology: 'react' },
          api: { type: 'backend', technology: 'typescript/express' },
        },
        access_control: {
          model: 'rbac_with_abac',
          roles: [
            {
              name: 'manager',
              permissions: [
                {
                  resource: 'employees',
                  actions: ['read', 'write'],
                  conditions: [{ field: 'user.department', operator: 'equals', value: 'HR' }],
                },
              ],
            },
          ],
          policies: [
            {
              name: 'manager_policy',
              resource: 'reports',
              action: 'approve',
              rules: [{ role: 'manager' }],
            },
          ],
        },
        stages: { local: { infrastructure: { databases: { primary: 'postgresql://localhost/test' }, services: {} } } },
      };

      const result = generator.generate({ workflow, outputDirectory: '/tmp/test' , executionPlan: { workflow, componentPlans: new Map() } });

      // Backend files
      expect(result.files.find(f => f.path.includes('api/src/types/access-control.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('api/src/config/roles.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('api/src/services/rbac.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('api/src/services/abac.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('api/src/services/authorization.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('api/src/services/policy-engine.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('api/src/middleware/authorization.ts'))).toBeDefined();

      // Frontend files
      expect(result.files.find(f => f.path.includes('web/src/hooks/usePermissions.ts'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('web/src/components/Can.tsx'))).toBeDefined();
      expect(result.files.find(f => f.path.includes('web/src/providers/AuthorizationProvider.tsx'))).toBeDefined();
    });
  });
});
