import { describe, it, expect, beforeEach, vi } from 'vitest';
import { RoadmapManager } from '../roadmap-manager.js';
import { ConfigManager } from '../../../config/config-manager.js';
import {
  CreateRoadmapOptions,
  AddThemeOptions,
  CreateInitiativeOptions,
  AddFeatureOptions,
  ProductRoadmap,
  RoadmapTheme,
  Initiative,
  Feature
} from '../types.js';

// Mock the storage manager
vi.mock('../../../storage/storage-manager.js', () => ({
  StorageManager: vi.fn().mockImplementation(() => ({
    getStorageLocation: vi.fn().mockResolvedValue({
      data: '/tmp/test-atlas'
    })
  }))
}));

// Mock fs operations
vi.mock('fs', () => ({
  promises: {
    access: vi.fn().mockRejectedValue(new Error('File not found')),
    mkdir: vi.fn().mockResolvedValue(undefined),
    readFile: vi.fn().mockRejectedValue(new Error('File not found')),
    writeFile: vi.fn().mockResolvedValue(undefined)
  }
}));

describe('RoadmapManager', () => {
  let roadmapManager: RoadmapManager;
  let configManager: ConfigManager;

  beforeEach(async () => {
    configManager = new ConfigManager();
    roadmapManager = new RoadmapManager(configManager);
    await roadmapManager.initialize();
  });

  describe('createRoadmap', () => {
    it('should create a new product roadmap', async () => {
      const options: CreateRoadmapOptions = {
        name: 'Test Product Roadmap',
        vision: 'To create an amazing product that users love',
        timeHorizon: 'annual',
        owner: 'John Doe',
        stakeholders: ['Jane Smith', 'Bob Johnson']
      };

      const roadmap = await roadmapManager.createRoadmap(options);

      expect(roadmap).toBeDefined();
      expect(roadmap.name).toBe(options.name);
      expect(roadmap.vision).toBe(options.vision);
      expect(roadmap.timeHorizon).toBe(options.timeHorizon);
      expect(roadmap.owner).toBe(options.owner);
      expect(roadmap.stakeholders).toEqual(options.stakeholders);
      expect(roadmap.status).toBe('draft');
      expect(roadmap.themes).toEqual([]);
      expect(roadmap.milestones).toEqual([]);
      expect(roadmap.releases).toEqual([]);
      expect(roadmap.metrics.featuresPlanned).toBe(0);
      expect(roadmap.metrics.featuresCompleted).toBe(0);
    });

    it('should generate unique IDs for roadmaps', async () => {
      const options: CreateRoadmapOptions = {
        name: 'Test Roadmap',
        vision: 'Test vision',
        timeHorizon: 'quarterly',
        owner: 'Test Owner'
      };

      const roadmap1 = await roadmapManager.createRoadmap(options);
      const roadmap2 = await roadmapManager.createRoadmap(options);

      expect(roadmap1.id).not.toBe(roadmap2.id);
    });
  });

  describe('addTheme', () => {
    let roadmap: ProductRoadmap;

    beforeEach(async () => {
      roadmap = await roadmapManager.createRoadmap({
        name: 'Test Roadmap',
        vision: 'Test vision',
        timeHorizon: 'annual',
        owner: 'Test Owner'
      });
    });

    it('should add a theme to a roadmap', async () => {
      const themeOptions: AddThemeOptions = {
        roadmapId: roadmap.id,
        name: 'User Experience Enhancement',
        description: 'Improve overall user experience across the platform',
        objectives: [
          'Reduce user friction',
          'Improve onboarding flow',
          'Enhance mobile experience'
        ],
        priority: 'must-have',
        startQuarter: 'Q1 2024',
        endQuarter: 'Q4 2024'
      };

      const theme = await roadmapManager.addTheme(themeOptions);

      expect(theme).toBeDefined();
      expect(theme.name).toBe(themeOptions.name);
      expect(theme.description).toBe(themeOptions.description);
      expect(theme.objectives).toEqual(themeOptions.objectives);
      expect(theme.priority).toBe(themeOptions.priority);
      expect(theme.timeframe.startQuarter).toBe(themeOptions.startQuarter);
      expect(theme.timeframe.endQuarter).toBe(themeOptions.endQuarter);
      expect(theme.status).toBe('planned');
      expect(theme.initiatives).toEqual([]);
      expect(theme.metrics.initiativesTotal).toBe(0);
    });

    it('should throw error for non-existent roadmap', async () => {
      const themeOptions: AddThemeOptions = {
        roadmapId: 'non-existent-roadmap',
        name: 'Test Theme',
        description: 'Test description',
        objectives: ['Test objective'],
        priority: 'nice-to-have',
        startQuarter: 'Q1 2024',
        endQuarter: 'Q2 2024'
      };

      await expect(roadmapManager.addTheme(themeOptions))
        .rejects.toThrow('Roadmap non-existent-roadmap not found');
    });
  });

  describe('createInitiative', () => {
    let roadmap: ProductRoadmap;
    let theme: RoadmapTheme;

    beforeEach(async () => {
      roadmap = await roadmapManager.createRoadmap({
        name: 'Test Roadmap',
        vision: 'Test vision',
        timeHorizon: 'annual',
        owner: 'Test Owner'
      });

      theme = await roadmapManager.addTheme({
        roadmapId: roadmap.id,
        name: 'Test Theme',
        description: 'Test description',
        objectives: ['Test objective'],
        priority: 'must-have',
        startQuarter: 'Q1 2024',
        endQuarter: 'Q4 2024'
      });
    });

    it('should create an initiative within a theme', async () => {
      const initiativeOptions: CreateInitiativeOptions = {
        roadmapId: roadmap.id,
        themeId: theme.id,
        title: 'Implement Smart Search',
        description: 'Build an AI-powered search system',
        estimatedValue: {
          userImpact: 'high',
          revenueImpact: 500000,
          costSavings: 200000,
          strategicValue: 8,
          customerSatisfaction: 15
        },
        estimatedEffort: {
          developmentWeeks: 12,
          designWeeks: 4,
          qaWeeks: 3,
          confidence: 'medium'
        },
        risks: [{
          id: 'risk-1',
          description: 'Technical complexity',
          likelihood: 'medium',
          impact: 'high',
          mitigation: 'Conduct technical spike'
        }]
      };

      const initiative = await roadmapManager.createInitiative(initiativeOptions);

      expect(initiative).toBeDefined();
      expect(initiative.themeId).toBe(theme.id);
      expect(initiative.title).toBe(initiativeOptions.title);
      expect(initiative.description).toBe(initiativeOptions.description);
      expect(initiative.value).toEqual(initiativeOptions.estimatedValue);
      expect(initiative.effort).toEqual(initiativeOptions.estimatedEffort);
      expect(initiative.risks).toHaveLength(1);
      expect(initiative.status).toBe('ideation');
      expect(initiative.features).toEqual([]);
      expect(initiative.epicIds).toEqual([]);
    });
  });

  describe('addFeature', () => {
    let roadmap: ProductRoadmap;
    let theme: RoadmapTheme;
    let initiative: Initiative;

    beforeEach(async () => {
      roadmap = await roadmapManager.createRoadmap({
        name: 'Test Roadmap',
        vision: 'Test vision',
        timeHorizon: 'annual',
        owner: 'Test Owner'
      });

      theme = await roadmapManager.addTheme({
        roadmapId: roadmap.id,
        name: 'Test Theme',
        description: 'Test description',
        objectives: ['Test objective'],
        priority: 'must-have',
        startQuarter: 'Q1 2024',
        endQuarter: 'Q4 2024'
      });

      initiative = await roadmapManager.createInitiative({
        roadmapId: roadmap.id,
        themeId: theme.id,
        title: 'Test Initiative',
        description: 'Test initiative description',
        estimatedValue: {
          userImpact: 'medium',
          revenueImpact: 100000,
          costSavings: 50000,
          strategicValue: 7,
          customerSatisfaction: 10
        },
        estimatedEffort: {
          developmentWeeks: 8,
          designWeeks: 2,
          qaWeeks: 2,
          confidence: 'high'
        }
      });
    });

    it('should add a feature to an initiative', async () => {
      const featureOptions: AddFeatureOptions = {
        roadmapId: roadmap.id,
        initiativeId: initiative.id,
        name: 'Natural Language Search',
        description: 'Allow users to search using natural language queries',
        businessValue: {
          score: 85,
          rationale: 'High user demand and competitive advantage',
          metrics: ['Search success rate > 90%', 'User satisfaction > 4.5/5']
        },
        technicalComplexity: 'high',
        targetRelease: 'v2.0'
      };

      const feature = await roadmapManager.addFeature(featureOptions);

      expect(feature).toBeDefined();
      expect(feature.initiativeId).toBe(initiative.id);
      expect(feature.name).toBe(featureOptions.name);
      expect(feature.description).toBe(featureOptions.description);
      expect(feature.businessValue).toEqual(featureOptions.businessValue);
      expect(feature.technicalComplexity).toBe(featureOptions.technicalComplexity);
      expect(feature.targetRelease).toBe(featureOptions.targetRelease);
      expect(feature.status).toBe('proposed');
      expect(feature.priority).toBe(0);
    });
  });

  describe('updateFeatureStatus', () => {
    let feature: Feature;

    beforeEach(async () => {
      const roadmap = await roadmapManager.createRoadmap({
        name: 'Test Roadmap',
        vision: 'Test vision',
        timeHorizon: 'annual',
        owner: 'Test Owner'
      });

      const theme = await roadmapManager.addTheme({
        roadmapId: roadmap.id,
        name: 'Test Theme',
        description: 'Test description',
        objectives: ['Test objective'],
        priority: 'must-have',
        startQuarter: 'Q1 2024',
        endQuarter: 'Q4 2024'
      });

      const initiative = await roadmapManager.createInitiative({
        roadmapId: roadmap.id,
        themeId: theme.id,
        title: 'Test Initiative',
        description: 'Test initiative',
        estimatedValue: {
          userImpact: 'medium',
          revenueImpact: 100000,
          costSavings: 50000,
          strategicValue: 7,
          customerSatisfaction: 10
        },
        estimatedEffort: {
          developmentWeeks: 8,
          designWeeks: 2,
          qaWeeks: 2,
          confidence: 'high'
        }
      });

      feature = await roadmapManager.addFeature({
        roadmapId: roadmap.id,
        initiativeId: initiative.id,
        name: 'Test Feature',
        description: 'Test feature description',
        businessValue: {
          score: 75,
          rationale: 'Test rationale',
          metrics: ['Test metric']
        },
        technicalComplexity: 'medium'
      });
    });

    it('should update feature status', async () => {
      const updatedFeature = await roadmapManager.updateFeatureStatus(
        feature.id,
        'in-progress'
      );

      expect(updatedFeature.status).toBe('in-progress');
    });

    it('should throw error for non-existent feature', async () => {
      await expect(roadmapManager.updateFeatureStatus('non-existent', 'completed'))
        .rejects.toThrow('Feature non-existent not found');
    });
  });

  describe('getRoadmapHealth', () => {
    let roadmap: ProductRoadmap;

    beforeEach(async () => {
      roadmap = await roadmapManager.createRoadmap({
        name: 'Test Roadmap',
        vision: 'Test vision',
        timeHorizon: 'annual',
        owner: 'Test Owner'
      });
    });

    it('should return health assessment for a roadmap', async () => {
      const health = await roadmapManager.getRoadmapHealth(roadmap.id);

      expect(health).toBeDefined();
      expect(health.health).toMatch(/excellent|good|at-risk|critical/);
      expect(health.metrics).toBeDefined();
      expect(health.risks).toBeInstanceOf(Array);
      expect(health.recommendations).toBeInstanceOf(Array);
    });

    it('should identify risks for low on-time delivery', async () => {
      // This would require mocking the roadmap metrics
      // For now, we just test the structure
      const health = await roadmapManager.getRoadmapHealth(roadmap.id);
      
      expect(health.metrics.onTimeDelivery).toBeDefined();
      expect(health.metrics.velocityTrend).toBeDefined();
    });
  });

  describe('getThemeDetails', () => {
    it('should return null for non-existent theme', async () => {
      const details = await roadmapManager.getThemeDetails('non-existent');
      expect(details).toBeNull();
    });
  });
});