import { promises as fs } from 'fs';
import path from 'path';
import { StorageManager } from '../../storage/storage-manager.js';
import {
  ProductRoadmap,
  RoadmapTheme,
  Initiative,
  Feature,
  Milestone,
  Release,
  RoadmapReview
} from './types.js';

export class RoadmapStore {
  private storageManager: StorageManager;
  private dataPath: string = '';
  private initialized: boolean = false;

  constructor() {
    this.storageManager = new StorageManager();
  }

  async initialize(): Promise<void> {
    if (this.initialized) return;
    
    const location = await this.storageManager.getStorageLocation();
    this.dataPath = path.join(location.data, 'roadmaps');
    
    // Ensure directory exists
    await fs.mkdir(this.dataPath, { recursive: true });
    
    this.initialized = true;
  }

  // Roadmap operations
  async saveRoadmap(roadmap: ProductRoadmap): Promise<void> {
    await this.ensureInitialized();
    const filePath = path.join(this.dataPath, `roadmap-${roadmap.id}.json`);
    await fs.writeFile(filePath, JSON.stringify(roadmap, null, 2));
  }

  async loadRoadmap(roadmapId: string): Promise<ProductRoadmap | null> {
    await this.ensureInitialized();
    const filePath = path.join(this.dataPath, `roadmap-${roadmapId}.json`);
    
    try {
      const data = await fs.readFile(filePath, 'utf-8');
      const roadmap = JSON.parse(data);
      
      // Convert dates
      roadmap.createdAt = new Date(roadmap.createdAt);
      roadmap.updatedAt = new Date(roadmap.updatedAt);
      
      // Convert milestone dates
      if (roadmap.milestones) {
        roadmap.milestones.forEach((m: Milestone) => {
          m.date = new Date(m.date);
        });
      }
      
      // Convert release dates
      if (roadmap.releases) {
        roadmap.releases.forEach((r: Release) => {
          r.date = new Date(r.date);
        });
      }
      
      return roadmap;
    } catch (error) {
      return null;
    }
  }

  async listRoadmaps(): Promise<string[]> {
    await this.ensureInitialized();
    
    try {
      const files = await fs.readdir(this.dataPath);
      return files
        .filter(f => f.startsWith('roadmap-') && f.endsWith('.json'))
        .map(f => f.replace('roadmap-', '').replace('.json', ''));
    } catch (error) {
      return [];
    }
  }

  async deleteRoadmap(roadmapId: string): Promise<void> {
    await this.ensureInitialized();
    const filePath = path.join(this.dataPath, `roadmap-${roadmapId}.json`);
    
    try {
      await fs.unlink(filePath);
    } catch (error) {
      // Ignore if file doesn't exist
    }
  }

  // Bulk data operations
  async saveBulkData(
    data: {
      themes: RoadmapTheme[];
      initiatives: Initiative[];
      features: Feature[];
      milestones: Milestone[];
      releases: Release[];
      reviews: RoadmapReview[];
    }
  ): Promise<void> {
    await this.ensureInitialized();
    
    // Save each data type
    await Promise.all([
      fs.writeFile(
        path.join(this.dataPath, 'themes.json'),
        JSON.stringify(data.themes, null, 2)
      ),
      fs.writeFile(
        path.join(this.dataPath, 'initiatives.json'),
        JSON.stringify(data.initiatives, null, 2)
      ),
      fs.writeFile(
        path.join(this.dataPath, 'features.json'),
        JSON.stringify(data.features, null, 2)
      ),
      fs.writeFile(
        path.join(this.dataPath, 'milestones.json'),
        JSON.stringify(data.milestones, null, 2)
      ),
      fs.writeFile(
        path.join(this.dataPath, 'releases.json'),
        JSON.stringify(data.releases, null, 2)
      ),
      fs.writeFile(
        path.join(this.dataPath, 'reviews.json'),
        JSON.stringify(data.reviews, null, 2)
      )
    ]);
  }

  async loadBulkData(): Promise<{
    themes: Map<string, RoadmapTheme>;
    initiatives: Map<string, Initiative>;
    features: Map<string, Feature>;
    milestones: Map<string, Milestone>;
    releases: Map<string, Release>;
    reviews: Map<string, RoadmapReview>;
  }> {
    await this.ensureInitialized();
    
    const result = {
      themes: new Map<string, RoadmapTheme>(),
      initiatives: new Map<string, Initiative>(),
      features: new Map<string, Feature>(),
      milestones: new Map<string, Milestone>(),
      releases: new Map<string, Release>(),
      reviews: new Map<string, RoadmapReview>()
    };
    
    // Load themes
    try {
      const themesData = await fs.readFile(
        path.join(this.dataPath, 'themes.json'),
        'utf-8'
      );
      const themes: RoadmapTheme[] = JSON.parse(themesData);
      themes.forEach(theme => result.themes.set(theme.id, theme));
    } catch (error) {
      // File doesn't exist yet
    }
    
    // Load initiatives
    try {
      const initiativesData = await fs.readFile(
        path.join(this.dataPath, 'initiatives.json'),
        'utf-8'
      );
      const initiatives: Initiative[] = JSON.parse(initiativesData);
      initiatives.forEach(init => result.initiatives.set(init.id, init));
    } catch (error) {
      // File doesn't exist yet
    }
    
    // Load features
    try {
      const featuresData = await fs.readFile(
        path.join(this.dataPath, 'features.json'),
        'utf-8'
      );
      const features: Feature[] = JSON.parse(featuresData);
      features.forEach(feat => result.features.set(feat.id, feat));
    } catch (error) {
      // File doesn't exist yet
    }
    
    // Load milestones
    try {
      const milestonesData = await fs.readFile(
        path.join(this.dataPath, 'milestones.json'),
        'utf-8'
      );
      const milestones: Milestone[] = JSON.parse(milestonesData);
      milestones.forEach(m => {
        m.date = new Date(m.date);
        result.milestones.set(m.id, m);
      });
    } catch (error) {
      // File doesn't exist yet
    }
    
    // Load releases
    try {
      const releasesData = await fs.readFile(
        path.join(this.dataPath, 'releases.json'),
        'utf-8'
      );
      const releases: Release[] = JSON.parse(releasesData);
      releases.forEach(r => {
        r.date = new Date(r.date);
        result.releases.set(r.id, r);
      });
    } catch (error) {
      // File doesn't exist yet
    }
    
    // Load reviews
    try {
      const reviewsData = await fs.readFile(
        path.join(this.dataPath, 'reviews.json'),
        'utf-8'
      );
      const reviews: RoadmapReview[] = JSON.parse(reviewsData);
      reviews.forEach(review => {
        review.reviewDate = new Date(review.reviewDate);
        if (review.nextReviewDate) {
          review.nextReviewDate = new Date(review.nextReviewDate);
        }
        result.reviews.set(review.id, review);
      });
    } catch (error) {
      // File doesn't exist yet
    }
    
    return result;
  }

  // Index operations for efficient queries
  async buildIndices(): Promise<{
    roadmapThemes: Map<string, string[]>; // roadmapId -> themeIds
    themeInitiatives: Map<string, string[]>; // themeId -> initiativeIds
    initiativeFeatures: Map<string, string[]>; // initiativeId -> featureIds
    releaseFeatures: Map<string, string[]>; // releaseId -> featureIds
  }> {
    await this.ensureInitialized();
    
    const indices = {
      roadmapThemes: new Map<string, string[]>(),
      themeInitiatives: new Map<string, string[]>(),
      initiativeFeatures: new Map<string, string[]>(),
      releaseFeatures: new Map<string, string[]>()
    };
    
    // Build indices from roadmaps
    const roadmapIds = await this.listRoadmaps();
    for (const roadmapId of roadmapIds) {
      const roadmap = await this.loadRoadmap(roadmapId);
      if (roadmap) {
        indices.roadmapThemes.set(
          roadmapId,
          roadmap.themes.map(t => typeof t === 'string' ? t : t.id)
        );
      }
    }
    
    // Build other indices from bulk data
    const bulkData = await this.loadBulkData();
    
    // Theme -> Initiatives
    for (const [themeId, theme] of bulkData.themes) {
      indices.themeInitiatives.set(
        themeId,
        theme.initiatives.map(i => typeof i === 'string' ? i : i.id)
      );
    }
    
    // Initiative -> Features
    for (const [initId, initiative] of bulkData.initiatives) {
      indices.initiativeFeatures.set(
        initId,
        initiative.features.map(f => typeof f === 'string' ? f : f.id)
      );
    }
    
    // Release -> Features
    for (const [releaseId, release] of bulkData.releases) {
      indices.releaseFeatures.set(releaseId, release.features);
    }
    
    return indices;
  }

  // Export/Import operations
  async exportRoadmap(roadmapId: string): Promise<string> {
    await this.ensureInitialized();
    
    const roadmap = await this.loadRoadmap(roadmapId);
    if (!roadmap) {
      throw new Error(`Roadmap ${roadmapId} not found`);
    }
    
    const bulkData = await this.loadBulkData();
    const exportData = {
      roadmap,
      themes: [] as RoadmapTheme[],
      initiatives: [] as Initiative[],
      features: [] as Feature[],
      milestones: [] as Milestone[],
      releases: [] as Release[]
    };
    
    // Collect related data
    for (const theme of roadmap.themes) {
      const themeId = typeof theme === 'string' ? theme : theme.id;
      const themeData = bulkData.themes.get(themeId);
      if (themeData) {
        exportData.themes.push(themeData);
        
        // Collect initiatives
        for (const init of themeData.initiatives) {
          const initId = typeof init === 'string' ? init : init.id;
          const initData = bulkData.initiatives.get(initId);
          if (initData) {
            exportData.initiatives.push(initData);
            
            // Collect features
            for (const feat of initData.features) {
              const featId = typeof feat === 'string' ? feat : feat.id;
              const featData = bulkData.features.get(featId);
              if (featData) {
                exportData.features.push(featData);
              }
            }
          }
        }
      }
    }
    
    // Collect milestones
    for (const milestone of roadmap.milestones) {
      const milestoneId = typeof milestone === 'string' ? milestone : milestone.id;
      const milestoneData = bulkData.milestones.get(milestoneId);
      if (milestoneData) {
        exportData.milestones.push(milestoneData);
      }
    }
    
    // Collect releases
    for (const release of roadmap.releases) {
      const releaseId = typeof release === 'string' ? release : release.id;
      const releaseData = bulkData.releases.get(releaseId);
      if (releaseData) {
        exportData.releases.push(releaseData);
      }
    }
    
    return JSON.stringify(exportData, null, 2);
  }

  async importRoadmap(jsonData: string): Promise<string> {
    await this.ensureInitialized();
    
    const importData = JSON.parse(jsonData);
    const roadmap = importData.roadmap;
    
    // Generate new IDs to avoid conflicts
    const idMap = new Map<string, string>();
    
    // Generate new roadmap ID
    const newRoadmapId = `roadmap-${this.generateId()}`;
    idMap.set(roadmap.id, newRoadmapId);
    roadmap.id = newRoadmapId;
    
    // Update theme IDs
    if (importData.themes) {
      for (const theme of importData.themes) {
        const newId = `theme-${this.generateId()}`;
        idMap.set(theme.id, newId);
        theme.id = newId;
      }
    }
    
    // Update initiative IDs
    if (importData.initiatives) {
      for (const init of importData.initiatives) {
        const newId = `initiative-${this.generateId()}`;
        idMap.set(init.id, newId);
        init.id = newId;
        init.themeId = idMap.get(init.themeId) || init.themeId;
      }
    }
    
    // Update feature IDs
    if (importData.features) {
      for (const feat of importData.features) {
        const newId = `feature-${this.generateId()}`;
        idMap.set(feat.id, newId);
        feat.id = newId;
        feat.initiativeId = idMap.get(feat.initiativeId) || feat.initiativeId;
      }
    }
    
    // Update references in roadmap
    roadmap.themes = roadmap.themes.map((t: any) => 
      idMap.get(typeof t === 'string' ? t : t.id) || t
    );
    
    // Update references in themes
    if (importData.themes) {
      for (const theme of importData.themes) {
        theme.initiatives = theme.initiatives.map((i: any) =>
          idMap.get(typeof i === 'string' ? i : i.id) || i
        );
      }
    }
    
    // Update references in initiatives
    if (importData.initiatives) {
      for (const init of importData.initiatives) {
        init.features = init.features.map((f: any) =>
          idMap.get(typeof f === 'string' ? f : f.id) || f
        );
      }
    }
    
    // Save imported data
    await this.saveRoadmap(roadmap);
    
    const bulkData = await this.loadBulkData();
    
    // Merge imported data
    if (importData.themes) {
      importData.themes.forEach((t: RoadmapTheme) => bulkData.themes.set(t.id, t));
    }
    if (importData.initiatives) {
      importData.initiatives.forEach((i: Initiative) => bulkData.initiatives.set(i.id, i));
    }
    if (importData.features) {
      importData.features.forEach((f: Feature) => bulkData.features.set(f.id, f));
    }
    if (importData.milestones) {
      importData.milestones.forEach((m: Milestone) => bulkData.milestones.set(m.id, m));
    }
    if (importData.releases) {
      importData.releases.forEach((r: Release) => bulkData.releases.set(r.id, r));
    }
    
    await this.saveBulkData({
      themes: Array.from(bulkData.themes.values()),
      initiatives: Array.from(bulkData.initiatives.values()),
      features: Array.from(bulkData.features.values()),
      milestones: Array.from(bulkData.milestones.values()),
      releases: Array.from(bulkData.releases.values()),
      reviews: Array.from(bulkData.reviews.values())
    });
    
    return newRoadmapId;
  }

  private async ensureInitialized(): Promise<void> {
    if (!this.initialized) {
      await this.initialize();
    }
  }

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