import { StorageManager } from '../../storage/storage-manager.js';
import { ConfigManager } from '../../config/config-manager.js';
import {
  AnalysisResult,
  CodeReview,
  MetricsHistory,
  HistoryEntry,
  CodeMetrics,
} from './types.js';

export class CodeAnalysisStore {
  private storageManager: StorageManager;
  private moduleName = 'code-analysis';

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

  async initialize(): Promise<void> {
    await this.storageManager.ensureStorageDirectories();
  }

  // Analysis History Management

  async saveAnalysisResult(result: AnalysisResult): Promise<void> {
    let history: AnalysisResult[] = [];
    try {
      history = await this.storageManager.loadData(this.moduleName, 'analysis-history.json') || [];
    } catch {
      // File doesn't exist yet
    }

    history.push(result);

    // Keep only last 50 analyses
    if (history.length > 50) {
      history = history.slice(-50);
    }

    await this.storageManager.saveData(this.moduleName, 'analysis-history.json', history);
  }

  async getAnalysisHistory(limit?: number): Promise<AnalysisResult[]> {
    try {
      const history = await this.storageManager.loadData(this.moduleName, 'analysis-history.json') as AnalysisResult[];
      
      if (limit && limit > 0) {
        return (history || []).slice(-limit);
      }
      
      return history || [];
    } catch {
      return [];
    }
  }

  async getLatestAnalysis(): Promise<AnalysisResult | null> {
    const history = await this.getAnalysisHistory(1);
    return history.length > 0 ? history[0] : null;
  }

  // Code Review Management

  async saveCodeReview(review: CodeReview): Promise<void> {
    let reviews: CodeReview[] = [];
    try {
      reviews = await this.storageManager.loadData(this.moduleName, 'code-reviews.json') || [];
    } catch {
      // File doesn't exist yet
    }

    reviews.push(review);

    // Keep only last 100 reviews
    if (reviews.length > 100) {
      reviews = reviews.slice(-100);
    }

    await this.storageManager.saveData(this.moduleName, 'code-reviews.json', reviews);
  }

  async getCodeReviews(fileFilter?: string): Promise<CodeReview[]> {
    try {
      const reviews = await this.storageManager.loadData(this.moduleName, 'code-reviews.json') as CodeReview[];
      
      if (fileFilter) {
        return (reviews || []).filter(review => review.file.includes(fileFilter));
      }
      
      return reviews || [];
    } catch {
      return [];
    }
  }

  // Metrics History Management

  async saveMetricsHistory(projectId: string, entry: HistoryEntry): Promise<void> {
    let history: MetricsHistory;
    
    try {
      history = await this.storageManager.loadData(this.moduleName, `metrics-${projectId}.json`) || {
        projectId,
        entries: [],
        baseline: undefined,
      };
    } catch {
      history = {
        projectId,
        entries: [],
        baseline: undefined,
        trends: [],
      };
    }

    history.entries.push(entry);

    // Keep only last 30 days of entries
    const thirtyDaysAgo = new Date();
    thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
    
    history.entries = history.entries.filter(e => 
      new Date(e.timestamp) > thirtyDaysAgo
    );

    await this.storageManager.saveData(this.moduleName, `metrics-${projectId}.json`, history);
  }

  async getMetricsHistory(projectId: string): Promise<MetricsHistory | null> {
    try {
      return await this.storageManager.loadData(this.moduleName, `metrics-${projectId}.json`);
    } catch {
      return null;
    }
  }

  async setBaseline(projectId: string, commit: string, metrics: CodeMetrics): Promise<void> {
    let history = await this.getMetricsHistory(projectId);
    
    if (!history) {
      history = {
        projectId,
        entries: [],
        baseline: undefined,
        trends: [],
      };
    }

    history.baseline = {
      timestamp: new Date().toISOString(),
      branch: 'main',
      commit,
      metrics,
    };

    await this.storageManager.saveData(this.moduleName, `metrics-${projectId}.json`, history);
  }

  // Trend Analysis

  async getMetricsTrend(
    projectId: string,
    metricPath: string,
    days: number = 7
  ): Promise<Array<{ timestamp: string; value: number }>> {
    const history = await this.getMetricsHistory(projectId);
    
    if (!history) {
      return [];
    }

    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days);

    const trend = history.entries
      .filter(entry => new Date(entry.timestamp) > startDate)
      .map(entry => {
        const value = this.getNestedValue(entry.metrics, metricPath);
        return {
          timestamp: entry.timestamp,
          value: typeof value === 'number' ? value : 0,
        };
      })
      .filter(item => item.value !== 0);

    return trend;
  }

  async getQualityScore(projectId: string): Promise<number> {
    const history = await this.getMetricsHistory(projectId);
    
    if (!history || history.entries.length === 0) {
      return 0;
    }

    const latestEntry = history.entries[history.entries.length - 1];
    const metrics = latestEntry.metrics;

    // Calculate weighted quality score
    const complexityScore = Math.max(0, 100 - metrics.complexity.average * 5);
    const maintainabilityScore = metrics.maintainability.average;
    const duplicationScore = Math.max(0, 100 - metrics.duplication.percentage);
    const issuesScore = Math.max(0, 100 - metrics.quality.issues.total * 2);

    const qualityScore = (
      complexityScore * 0.25 +
      maintainabilityScore * 0.35 +
      duplicationScore * 0.2 +
      issuesScore * 0.2
    );

    return Math.round(qualityScore);
  }

  private getNestedValue(obj: any, path: string): any {
    const keys = path.split('.');
    let current = obj;
    
    for (const key of keys) {
      if (current && typeof current === 'object' && key in current) {
        current = current[key];
      } else {
        return undefined;
      }
    }
    
    return current;
  }

  // Custom Rules Management

  async saveCustomRules(projectId: string, rules: any[]): Promise<void> {
    await this.storageManager.saveData(this.moduleName, `rules-${projectId}.json`, rules);
  }

  async getCustomRules(projectId: string): Promise<any[]> {
    try {
      return await this.storageManager.loadData(this.moduleName, `rules-${projectId}.json`) || [];
    } catch {
      return [];
    }
  }

  // Export/Import

  async exportAnalysisData(projectId: string): Promise<any> {
    const [
      history,
      reviews,
      metrics,
      rules,
    ] = await Promise.all([
      this.getAnalysisHistory(),
      this.getCodeReviews(),
      this.getMetricsHistory(projectId),
      this.getCustomRules(projectId),
    ]);

    return {
      analysisHistory: history,
      codeReviews: reviews,
      metricsHistory: metrics,
      customRules: rules,
      exportedAt: new Date().toISOString(),
    };
  }

  async importAnalysisData(projectId: string, data: any): Promise<void> {
    if (data.analysisHistory) {
      await this.storageManager.saveData(this.moduleName, 'analysis-history.json', data.analysisHistory);
    }

    if (data.codeReviews) {
      await this.storageManager.saveData(this.moduleName, 'code-reviews.json', data.codeReviews);
    }

    if (data.metricsHistory) {
      await this.storageManager.saveData(this.moduleName, `metrics-${projectId}.json`, data.metricsHistory);
    }

    if (data.customRules) {
      await this.storageManager.saveData(this.moduleName, `rules-${projectId}.json`, data.customRules);
    }
  }

  // Cleanup

  async cleanupOldData(daysToKeep: number = 30): Promise<number> {
    let cleanedItems = 0;

    // Clean analysis history
    const history = await this.getAnalysisHistory();
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);

    const filteredHistory = history.filter(item => 
      new Date(item.timestamp) > cutoffDate
    );

    if (filteredHistory.length < history.length) {
      await this.storageManager.saveData(this.moduleName, 'analysis-history.json', filteredHistory);
      cleanedItems += history.length - filteredHistory.length;
    }

    // Clean code reviews
    const reviews = await this.getCodeReviews();
    const filteredReviews = reviews.filter(review => 
      new Date(review.timestamp) > cutoffDate
    );

    if (filteredReviews.length < reviews.length) {
      await this.storageManager.saveData(this.moduleName, 'code-reviews.json', filteredReviews);
      cleanedItems += reviews.length - filteredReviews.length;
    }

    return cleanedItems;
  }
}