import { ConfigManager } from '../../config/config-manager.js';
import { StorageManager } from '../../storage/storage-manager.js';
import {
  ProductRoadmap,
  RoadmapTheme,
  Initiative,
  Feature,
  Milestone,
  Release,
  CreateRoadmapOptions,
  AddThemeOptions,
  CreateInitiativeOptions,
  AddFeatureOptions,
  RoadmapMetrics,
  ThemeMetrics,
  ValueMetrics,
  TimelineView,
  TimelineItem,
  RoadmapReview,
  ReviewDecision,
  ReviewFeedback
} from './types.js';
import { promises as fs } from 'fs';
import path from 'path';

export class RoadmapManager {
  private configManager: ConfigManager;
  private storageManager: StorageManager;
  private roadmapDataPath: string;
  private roadmaps: Map<string, ProductRoadmap>;
  private themes: Map<string, RoadmapTheme>;
  private initiatives: Map<string, Initiative>;
  private features: Map<string, Feature>;
  private milestones: Map<string, Milestone>;
  private releases: Map<string, Release>;
  private reviews: Map<string, RoadmapReview>;

  constructor(configManager: ConfigManager) {
    this.configManager = configManager;
    this.storageManager = new StorageManager();
    this.roadmapDataPath = '';
    this.roadmaps = new Map();
    this.themes = new Map();
    this.initiatives = new Map();
    this.features = new Map();
    this.milestones = new Map();
    this.releases = new Map();
    this.reviews = new Map();
  }

  async initialize(): Promise<void> {
    const location = await this.storageManager.getStorageLocation();
    this.roadmapDataPath = path.join(location.data, 'roadmaps');
    await this.loadExistingData();
  }

  private async loadExistingData(): Promise<void> {
    try {
      // Load roadmaps
      const roadmapsPath = path.join(this.roadmapDataPath, 'roadmaps.json');
      if (await this.fileExists(roadmapsPath)) {
        const roadmapsData = JSON.parse(await fs.readFile(roadmapsPath, 'utf-8'));
        roadmapsData.forEach((roadmap: ProductRoadmap) => {
          roadmap.createdAt = new Date(roadmap.createdAt);
          roadmap.updatedAt = new Date(roadmap.updatedAt);
          this.roadmaps.set(roadmap.id, roadmap);
        });
      }

      // Load themes
      const themesPath = path.join(this.roadmapDataPath, 'themes.json');
      if (await this.fileExists(themesPath)) {
        const themesData = JSON.parse(await fs.readFile(themesPath, 'utf-8'));
        themesData.forEach((theme: RoadmapTheme) => {
          this.themes.set(theme.id, theme);
        });
      }

      // Load initiatives
      const initiativesPath = path.join(this.roadmapDataPath, 'initiatives.json');
      if (await this.fileExists(initiativesPath)) {
        const initiativesData = JSON.parse(await fs.readFile(initiativesPath, 'utf-8'));
        initiativesData.forEach((initiative: Initiative) => {
          this.initiatives.set(initiative.id, initiative);
        });
      }

      // Load features
      const featuresPath = path.join(this.roadmapDataPath, 'features.json');
      if (await this.fileExists(featuresPath)) {
        const featuresData = JSON.parse(await fs.readFile(featuresPath, 'utf-8'));
        featuresData.forEach((feature: Feature) => {
          this.features.set(feature.id, feature);
        });
      }

      // Load milestones
      const milestonesPath = path.join(this.roadmapDataPath, 'milestones.json');
      if (await this.fileExists(milestonesPath)) {
        const milestonesData = JSON.parse(await fs.readFile(milestonesPath, 'utf-8'));
        milestonesData.forEach((milestone: Milestone) => {
          milestone.date = new Date(milestone.date);
          this.milestones.set(milestone.id, milestone);
        });
      }

      // Load releases
      const releasesPath = path.join(this.roadmapDataPath, 'releases.json');
      if (await this.fileExists(releasesPath)) {
        const releasesData = JSON.parse(await fs.readFile(releasesPath, 'utf-8'));
        releasesData.forEach((release: Release) => {
          release.date = new Date(release.date);
          this.releases.set(release.id, release);
        });
      }
    } catch (error) {
      console.error('Error loading roadmap data:', error);
    }
  }

  private async fileExists(filePath: string): Promise<boolean> {
    try {
      await fs.access(filePath);
      return true;
    } catch {
      return false;
    }
  }

  async createRoadmap(options: CreateRoadmapOptions): Promise<ProductRoadmap> {
    const roadmap: ProductRoadmap = {
      id: `roadmap-${this.generateId()}`,
      name: options.name,
      vision: options.vision,
      timeHorizon: options.timeHorizon,
      status: 'draft',
      themes: [],
      milestones: [],
      releases: [],
      createdAt: new Date(),
      updatedAt: new Date(),
      owner: options.owner,
      stakeholders: options.stakeholders || [],
      metrics: {
        featuresPlanned: 0,
        featuresCompleted: 0,
        initiativesActive: 0,
        velocityTrend: 'stable',
        onTimeDelivery: 100,
        valueDelivered: 0
      }
    };

    this.roadmaps.set(roadmap.id, roadmap);
    await this.saveRoadmaps();
    
    return roadmap;
  }

  async addTheme(options: AddThemeOptions): Promise<RoadmapTheme> {
    const roadmap = this.roadmaps.get(options.roadmapId);
    if (!roadmap) {
      throw new Error(`Roadmap ${options.roadmapId} not found`);
    }

    const theme: RoadmapTheme = {
      id: `theme-${this.generateId()}`,
      name: options.name,
      description: options.description,
      objectives: options.objectives,
      initiatives: [],
      priority: options.priority,
      timeframe: {
        startQuarter: options.startQuarter,
        endQuarter: options.endQuarter
      },
      status: 'planned',
      metrics: {
        initiativesTotal: 0,
        initiativesCompleted: 0,
        featuresTotal: 0,
        featuresCompleted: 0,
        progressPercentage: 0,
        valueScore: 0
      }
    };

    this.themes.set(theme.id, theme);
    roadmap.themes.push(theme);
    roadmap.updatedAt = new Date();
    
    await Promise.all([this.saveThemes(), this.saveRoadmaps()]);
    
    return theme;
  }

  async createInitiative(options: CreateInitiativeOptions): Promise<Initiative> {
    const roadmap = this.roadmaps.get(options.roadmapId);
    const theme = this.themes.get(options.themeId);
    
    if (!roadmap) {
      throw new Error(`Roadmap ${options.roadmapId} not found`);
    }
    if (!theme) {
      throw new Error(`Theme ${options.themeId} not found`);
    }

    const initiative: Initiative = {
      id: `initiative-${this.generateId()}`,
      themeId: options.themeId,
      title: options.title,
      description: options.description,
      features: [],
      epicIds: [],
      value: options.estimatedValue,
      effort: options.estimatedEffort,
      risks: options.risks || [],
      dependencies: [],
      status: 'ideation'
    };

    this.initiatives.set(initiative.id, initiative);
    theme.initiatives.push(initiative);
    
    // Update theme metrics
    theme.metrics.initiativesTotal++;
    this.updateRoadmapMetrics(roadmap);
    
    await Promise.all([
      this.saveInitiatives(),
      this.saveThemes(),
      this.saveRoadmaps()
    ]);
    
    return initiative;
  }

  async addFeature(options: AddFeatureOptions): Promise<Feature> {
    const roadmap = this.roadmaps.get(options.roadmapId);
    const initiative = this.initiatives.get(options.initiativeId);
    
    if (!roadmap) {
      throw new Error(`Roadmap ${options.roadmapId} not found`);
    }
    if (!initiative) {
      throw new Error(`Initiative ${options.initiativeId} not found`);
    }

    const feature: Feature = {
      id: `feature-${this.generateId()}`,
      initiativeId: options.initiativeId,
      name: options.name,
      description: options.description,
      userStories: [],
      priority: 0, // Will be set by prioritization
      businessValue: options.businessValue,
      technicalComplexity: options.technicalComplexity,
      targetRelease: options.targetRelease,
      status: 'proposed'
    };

    this.features.set(feature.id, feature);
    initiative.features.push(feature);
    
    // Update metrics
    const theme = this.themes.get(initiative.themeId);
    if (theme) {
      theme.metrics.featuresTotal++;
    }
    roadmap.metrics.featuresPlanned++;
    this.updateRoadmapMetrics(roadmap);
    
    await Promise.all([
      this.saveFeatures(),
      this.saveInitiatives(),
      this.saveThemes(),
      this.saveRoadmaps()
    ]);
    
    return feature;
  }

  async createMilestone(roadmapId: string, milestone: Omit<Milestone, 'id'>): Promise<Milestone> {
    const roadmap = this.roadmaps.get(roadmapId);
    if (!roadmap) {
      throw new Error(`Roadmap ${roadmapId} not found`);
    }

    const newMilestone: Milestone = {
      ...milestone,
      id: `milestone-${this.generateId()}`,
      date: new Date(milestone.date),
      status: 'upcoming'
    };

    this.milestones.set(newMilestone.id, newMilestone);
    roadmap.milestones.push(newMilestone);
    roadmap.updatedAt = new Date();
    
    await Promise.all([this.saveMilestones(), this.saveRoadmaps()]);
    
    return newMilestone;
  }

  async planRelease(roadmapId: string, release: Omit<Release, 'id' | 'status'>): Promise<Release> {
    const roadmap = this.roadmaps.get(roadmapId);
    if (!roadmap) {
      throw new Error(`Roadmap ${roadmapId} not found`);
    }

    const newRelease: Release = {
      ...release,
      id: `release-${this.generateId()}`,
      date: new Date(release.date),
      status: 'planning'
    };

    this.releases.set(newRelease.id, newRelease);
    roadmap.releases.push(newRelease);
    roadmap.updatedAt = new Date();
    
    await Promise.all([this.saveReleases(), this.saveRoadmaps()]);
    
    return newRelease;
  }

  async updateFeatureStatus(featureId: string, status: Feature['status']): Promise<Feature> {
    const feature = this.features.get(featureId);
    if (!feature) {
      throw new Error(`Feature ${featureId} not found`);
    }

    feature.status = status;
    
    // Update metrics if completed
    if (status === 'completed') {
      const initiative = this.initiatives.get(feature.initiativeId);
      if (initiative) {
        const theme = this.themes.get(initiative.themeId);
        if (theme) {
          theme.metrics.featuresCompleted++;
          this.updateThemeProgress(theme);
        }
      }
      
      // Find and update roadmap
      for (const [, roadmap] of this.roadmaps) {
        if (roadmap.themes.some(t => t.id === initiative?.themeId)) {
          roadmap.metrics.featuresCompleted++;
          this.updateRoadmapMetrics(roadmap);
          break;
        }
      }
    }
    
    await this.saveFeatures();
    
    return feature;
  }

  async updateInitiativeStatus(initiativeId: string, status: Initiative['status']): Promise<Initiative> {
    const initiative = this.initiatives.get(initiativeId);
    if (!initiative) {
      throw new Error(`Initiative ${initiativeId} not found`);
    }

    initiative.status = status;
    
    // Update theme metrics if completed
    if (status === 'launched') {
      const theme = this.themes.get(initiative.themeId);
      if (theme) {
        theme.metrics.initiativesCompleted++;
        this.updateThemeProgress(theme);
      }
    }
    
    await this.saveInitiatives();
    
    return initiative;
  }

  async generateTimeline(roadmapId: string, viewType: TimelineView['type']): Promise<TimelineView> {
    const roadmap = this.roadmaps.get(roadmapId);
    if (!roadmap) {
      throw new Error(`Roadmap ${roadmapId} not found`);
    }

    const items: TimelineItem[] = [];
    const now = new Date();
    
    // Add themes to timeline
    for (const theme of roadmap.themes) {
      const startDate = this.parseQuarter(theme.timeframe.startQuarter);
      const endDate = this.parseQuarter(theme.timeframe.endQuarter);
      
      items.push({
        id: theme.id,
        type: 'theme',
        name: theme.name,
        startDate,
        endDate,
        status: theme.status,
        dependencies: [],
        progress: theme.metrics.progressPercentage
      });
    }
    
    // Add milestones
    for (const milestone of roadmap.milestones) {
      items.push({
        id: milestone.id,
        type: 'milestone',
        name: milestone.name,
        startDate: milestone.date,
        endDate: milestone.date,
        status: milestone.status,
        dependencies: milestone.dependencies
      });
    }
    
    // Add releases
    for (const release of roadmap.releases) {
      items.push({
        id: release.id,
        type: 'release',
        name: `${release.version} - ${release.name}`,
        startDate: release.date,
        endDate: release.date,
        status: release.status,
        dependencies: []
      });
    }
    
    // Sort by start date
    items.sort((a, b) => a.startDate.getTime() - b.startDate.getTime());
    
    return {
      type: viewType,
      startDate: items[0]?.startDate || now,
      endDate: items[items.length - 1]?.endDate || now,
      items
    };
  }

  async getRoadmapHealth(roadmapId: string): Promise<{
    health: 'excellent' | 'good' | 'at-risk' | 'critical';
    metrics: RoadmapMetrics;
    risks: string[];
    recommendations: string[];
  }> {
    const roadmap = this.roadmaps.get(roadmapId);
    if (!roadmap) {
      throw new Error(`Roadmap ${roadmapId} not found`);
    }

    const risks: string[] = [];
    const recommendations: string[] = [];
    
    // Analyze on-time delivery
    if (roadmap.metrics.onTimeDelivery < 70) {
      risks.push('Low on-time delivery rate');
      recommendations.push('Review capacity planning and estimates');
    }
    
    // Check velocity trend
    if (roadmap.metrics.velocityTrend === 'decreasing') {
      risks.push('Decreasing velocity trend');
      recommendations.push('Investigate blockers and team capacity');
    }
    
    // Calculate health score
    let healthScore = 100;
    if (roadmap.metrics.onTimeDelivery < 80) healthScore -= 20;
    if (roadmap.metrics.velocityTrend === 'decreasing') healthScore -= 20;
    if (roadmap.metrics.featuresCompleted / roadmap.metrics.featuresPlanned < 0.5) healthScore -= 20;
    
    const health = healthScore >= 80 ? 'excellent' :
                  healthScore >= 60 ? 'good' :
                  healthScore >= 40 ? 'at-risk' : 'critical';
    
    return {
      health,
      metrics: roadmap.metrics,
      risks,
      recommendations
    };
  }

  async getRoadmaps(): Promise<ProductRoadmap[]> {
    return Array.from(this.roadmaps.values())
      .filter(r => r.status !== 'archived')
      .sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
  }

  async getRoadmap(roadmapId: string): Promise<ProductRoadmap | null> {
    return this.roadmaps.get(roadmapId) || null;
  }

  async getThemeDetails(themeId: string): Promise<{
    theme: RoadmapTheme;
    initiatives: Initiative[];
    features: Feature[];
  } | null> {
    const theme = this.themes.get(themeId);
    if (!theme) return null;

    const initiatives = theme.initiatives.map(i => 
      this.initiatives.get(typeof i === 'string' ? i : i.id)
    ).filter(Boolean) as Initiative[];

    const features: Feature[] = [];
    for (const initiative of initiatives) {
      const initiativeFeatures = initiative.features.map(f =>
        this.features.get(typeof f === 'string' ? f : f.id)
      ).filter(Boolean) as Feature[];
      features.push(...initiativeFeatures);
    }

    return { theme, initiatives, features };
  }

  private updateRoadmapMetrics(roadmap: ProductRoadmap): void {
    // Count active initiatives
    let activeInitiatives = 0;
    for (const theme of roadmap.themes) {
      for (const initiative of theme.initiatives) {
        const init = typeof initiative === 'string' ? 
          this.initiatives.get(initiative) : initiative;
        if (init && ['validated', 'scheduled', 'in-development'].includes(init.status)) {
          activeInitiatives++;
        }
      }
    }
    roadmap.metrics.initiativesActive = activeInitiatives;
    
    // Calculate value delivered
    let totalValue = 0;
    let completedValue = 0;
    
    for (const feature of this.features.values()) {
      if (feature.status === 'completed') {
        completedValue += feature.businessValue.score;
      }
      totalValue += feature.businessValue.score;
    }
    
    roadmap.metrics.valueDelivered = totalValue > 0 ? 
      Math.round((completedValue / totalValue) * 100) : 0;
  }

  private updateThemeProgress(theme: RoadmapTheme): void {
    const total = theme.metrics.initiativesTotal + theme.metrics.featuresTotal;
    const completed = theme.metrics.initiativesCompleted + theme.metrics.featuresCompleted;
    
    theme.metrics.progressPercentage = total > 0 ? 
      Math.round((completed / total) * 100) : 0;
  }

  private parseQuarter(quarter: string): Date {
    // Parse "Q1 2024" format
    const [q, year] = quarter.split(' ');
    const quarterNum = parseInt(q.substring(1));
    const yearNum = parseInt(year);
    
    // Q1 = Jan, Q2 = Apr, Q3 = Jul, Q4 = Oct
    const month = (quarterNum - 1) * 3;
    
    return new Date(yearNum, month, 1);
  }

  private generateId(): string {
    return `${Date.now().toString(16)}-${Math.random().toString(16).substr(2, 8)}`;
  }

  // Save methods
  private async saveRoadmaps(): Promise<void> {
    const roadmapsPath = path.join(this.roadmapDataPath, 'roadmaps.json');
    await fs.mkdir(path.dirname(roadmapsPath), { recursive: true });
    await fs.writeFile(roadmapsPath, JSON.stringify(Array.from(this.roadmaps.values()), null, 2));
  }

  private async saveThemes(): Promise<void> {
    const themesPath = path.join(this.roadmapDataPath, 'themes.json');
    await fs.mkdir(path.dirname(themesPath), { recursive: true });
    await fs.writeFile(themesPath, JSON.stringify(Array.from(this.themes.values()), null, 2));
  }

  private async saveInitiatives(): Promise<void> {
    const initiativesPath = path.join(this.roadmapDataPath, 'initiatives.json');
    await fs.mkdir(path.dirname(initiativesPath), { recursive: true });
    await fs.writeFile(initiativesPath, JSON.stringify(Array.from(this.initiatives.values()), null, 2));
  }

  private async saveFeatures(): Promise<void> {
    const featuresPath = path.join(this.roadmapDataPath, 'features.json');
    await fs.mkdir(path.dirname(featuresPath), { recursive: true });
    await fs.writeFile(featuresPath, JSON.stringify(Array.from(this.features.values()), null, 2));
  }

  private async saveMilestones(): Promise<void> {
    const milestonesPath = path.join(this.roadmapDataPath, 'milestones.json');
    await fs.mkdir(path.dirname(milestonesPath), { recursive: true });
    await fs.writeFile(milestonesPath, JSON.stringify(Array.from(this.milestones.values()), null, 2));
  }

  private async saveReleases(): Promise<void> {
    const releasesPath = path.join(this.roadmapDataPath, 'releases.json');
    await fs.mkdir(path.dirname(releasesPath), { recursive: true });
    await fs.writeFile(releasesPath, JSON.stringify(Array.from(this.releases.values()), null, 2));
  }
}