/**
 * Service pour les filtres avancés Jira
 * Gère le filtrage par composant, version, type de ticket, etc.
 */

import {
  JiraTask,
  JiraAnalytics,
  JiraAnalyticsFilters,
  AvailableFilters,
  FilterOption,
} from '@/lib/types';
import { parseDate } from '@/lib/date-utils';

export class JiraAdvancedFiltersService {
  /**
   * Extrait toutes les options de filtrage disponibles depuis les données
   */
  static extractAvailableFilters(issues: JiraTask[]): AvailableFilters {
    const componentCounts = new Map<string, number>();
    const fixVersionCounts = new Map<string, number>();
    const issueTypeCounts = new Map<string, number>();
    const statusCounts = new Map<string, number>();
    const assigneeCounts = new Map<string, number>();
    const labelCounts = new Map<string, number>();
    const priorityCounts = new Map<string, number>();

    issues.forEach((issue) => {
      // Components
      if (issue.components) {
        issue.components.forEach((component) => {
          componentCounts.set(
            component.name,
            (componentCounts.get(component.name) || 0) + 1
          );
        });
      }

      // Fix Versions
      if (issue.fixVersions) {
        issue.fixVersions.forEach((version) => {
          fixVersionCounts.set(
            version.name,
            (fixVersionCounts.get(version.name) || 0) + 1
          );
        });
      }

      // Issue Types
      issueTypeCounts.set(
        issue.issuetype.name,
        (issueTypeCounts.get(issue.issuetype.name) || 0) + 1
      );

      // Statuses
      statusCounts.set(
        issue.status.name,
        (statusCounts.get(issue.status.name) || 0) + 1
      );

      // Assignees
      const assigneeName = issue.assignee?.displayName || 'Non assigné';
      assigneeCounts.set(
        assigneeName,
        (assigneeCounts.get(assigneeName) || 0) + 1
      );

      // Labels
      issue.labels.forEach((label) => {
        labelCounts.set(label, (labelCounts.get(label) || 0) + 1);
      });

      // Priorities
      if (issue.priority) {
        priorityCounts.set(
          issue.priority.name,
          (priorityCounts.get(issue.priority.name) || 0) + 1
        );
      }
    });

    return {
      components: this.mapToFilterOptions(componentCounts),
      fixVersions: this.mapToFilterOptions(fixVersionCounts),
      issueTypes: this.mapToFilterOptions(issueTypeCounts),
      statuses: this.mapToFilterOptions(statusCounts),
      assignees: this.mapToFilterOptions(assigneeCounts),
      labels: this.mapToFilterOptions(labelCounts),
      priorities: this.mapToFilterOptions(priorityCounts),
    };
  }

  /**
   * Applique les filtres aux données analytics
   */
  static applyFiltersToAnalytics(
    analytics: JiraAnalytics,
    filters: Partial<JiraAnalyticsFilters>,
    allIssues: JiraTask[]
  ): JiraAnalytics {
    // Filtrer les issues d'abord
    const filteredIssues = this.filterIssues(allIssues, filters);

    // Recalculer les métriques avec les issues filtrées
    return this.recalculateAnalytics(analytics, filteredIssues);
  }

  /**
   * Filtre la liste des issues selon les critères
   */
  static filterIssues(
    issues: JiraTask[],
    filters: Partial<JiraAnalyticsFilters>
  ): JiraTask[] {
    return issues.filter((issue) => {
      // Filtrage par composants
      if (filters.components && filters.components.length > 0) {
        const issueComponents = issue.components?.map((c) => c.name) || [];
        if (
          !filters.components.some((comp) => issueComponents.includes(comp))
        ) {
          return false;
        }
      }

      // Filtrage par versions
      if (filters.fixVersions && filters.fixVersions.length > 0) {
        const issueVersions = issue.fixVersions?.map((v) => v.name) || [];
        if (
          !filters.fixVersions.some((version) =>
            issueVersions.includes(version)
          )
        ) {
          return false;
        }
      }

      // Filtrage par types
      if (filters.issueTypes && filters.issueTypes.length > 0) {
        if (!filters.issueTypes.includes(issue.issuetype.name)) {
          return false;
        }
      }

      // Filtrage par statuts
      if (filters.statuses && filters.statuses.length > 0) {
        if (!filters.statuses.includes(issue.status.name)) {
          return false;
        }
      }

      // Filtrage par assignees
      if (filters.assignees && filters.assignees.length > 0) {
        const assigneeName = issue.assignee?.displayName || 'Non assigné';
        if (!filters.assignees.includes(assigneeName)) {
          return false;
        }
      }

      // Filtrage par labels
      if (filters.labels && filters.labels.length > 0) {
        if (!filters.labels.some((label) => issue.labels.includes(label))) {
          return false;
        }
      }

      // Filtrage par priorités
      if (filters.priorities && filters.priorities.length > 0) {
        const priorityName = issue.priority?.name;
        if (!priorityName || !filters.priorities.includes(priorityName)) {
          return false;
        }
      }

      // Filtrage par date
      if (filters.dateRange) {
        const issueDate = parseDate(issue.created);
        if (
          issueDate < filters.dateRange.from ||
          issueDate > filters.dateRange.to
        ) {
          return false;
        }
      }

      return true;
    });
  }

  /**
   * Recalcule les analytics avec un subset d'issues filtrées
   */
  private static recalculateAnalytics(
    originalAnalytics: JiraAnalytics,
    filteredIssues: JiraTask[]
  ): JiraAnalytics {
    // Pour une implémentation complète, il faudrait recalculer toutes les métriques
    // Ici on fait une version simplifiée qui garde la structure mais met à jour les counts

    const totalFilteredIssues = filteredIssues.length;

    // Calculer la nouvelle distribution par assignee
    const assigneeMap = new Map<
      string,
      { completed: number; inProgress: number; total: number }
    >();

    filteredIssues.forEach((issue) => {
      const assigneeName = issue.assignee?.displayName || 'Non assigné';
      const current = assigneeMap.get(assigneeName) || {
        completed: 0,
        inProgress: 0,
        total: 0,
      };
      current.total++;

      if (issue.status.category === 'Done') {
        current.completed++;
      } else if (issue.status.category === 'In Progress') {
        current.inProgress++;
      }

      assigneeMap.set(assigneeName, current);
    });

    const newIssuesDistribution = Array.from(assigneeMap.entries()).map(
      ([assignee, stats]) => ({
        assignee: assignee === 'Non assigné' ? '' : assignee,
        displayName: assignee,
        totalIssues: stats.total,
        completedIssues: stats.completed,
        inProgressIssues: stats.inProgress,
        percentage:
          totalFilteredIssues > 0
            ? (stats.total / totalFilteredIssues) * 100
            : 0,
        count: stats.total, // Ajout pour compatibilité
      })
    );

    // Calculer la nouvelle distribution par statut
    const statusMap = new Map<string, number>();
    filteredIssues.forEach((issue) => {
      statusMap.set(
        issue.status.name,
        (statusMap.get(issue.status.name) || 0) + 1
      );
    });

    const newStatusDistribution = Array.from(statusMap.entries()).map(
      ([status, count]) => ({
        status,
        count,
        percentage:
          totalFilteredIssues > 0 ? (count / totalFilteredIssues) * 100 : 0,
      })
    );

    // Calculer la nouvelle charge par assignee
    const newAssigneeWorkload = Array.from(assigneeMap.entries()).map(
      ([assignee, stats]) => ({
        assignee: assignee === 'Non assigné' ? '' : assignee,
        displayName: assignee,
        todoCount: stats.total - stats.completed - stats.inProgress,
        inProgressCount: stats.inProgress,
        reviewCount: 0, // Simplified
        totalActive: stats.total - stats.completed,
      })
    );

    return {
      ...originalAnalytics,
      project: {
        ...originalAnalytics.project,
        totalIssues: totalFilteredIssues,
      },
      teamMetrics: {
        ...originalAnalytics.teamMetrics,
        issuesDistribution: newIssuesDistribution,
      },
      workInProgress: {
        byStatus: newStatusDistribution,
        byAssignee: newAssigneeWorkload,
      },
    };
  }

  /**
   * Convertit une Map de counts en options de filtre triées
   */
  private static mapToFilterOptions(
    countMap: Map<string, number>
  ): FilterOption[] {
    return Array.from(countMap.entries())
      .map(([value, count]) => ({
        value,
        label: value,
        count,
      }))
      .sort((a, b) => b.count - a.count); // Trier par count décroissant
  }

  /**
   * Crée un filtre vide
   */
  static createEmptyFilters(): JiraAnalyticsFilters {
    return {
      components: [],
      fixVersions: [],
      issueTypes: [],
      statuses: [],
      assignees: [],
      labels: [],
      priorities: [],
    };
  }

  /**
   * Vérifie si des filtres sont actifs
   */
  static hasActiveFilters(filters: Partial<JiraAnalyticsFilters>): boolean {
    return !!(
      filters.components?.length ||
      filters.fixVersions?.length ||
      filters.issueTypes?.length ||
      filters.statuses?.length ||
      filters.assignees?.length ||
      filters.labels?.length ||
      filters.priorities?.length ||
      filters.dateRange
    );
  }

  /**
   * Compte le nombre total de filtres actifs
   */
  static countActiveFilters(filters: Partial<JiraAnalyticsFilters>): number {
    let count = 0;
    if (filters.components?.length) count += filters.components.length;
    if (filters.fixVersions?.length) count += filters.fixVersions.length;
    if (filters.issueTypes?.length) count += filters.issueTypes.length;
    if (filters.statuses?.length) count += filters.statuses.length;
    if (filters.assignees?.length) count += filters.assignees.length;
    if (filters.labels?.length) count += filters.labels.length;
    if (filters.priorities?.length) count += filters.priorities.length;
    if (filters.dateRange) count += 1;
    return count;
  }

  /**
   * Génère un résumé textuel des filtres actifs
   */
  static getFiltersSummary(filters: Partial<JiraAnalyticsFilters>): string {
    const parts: string[] = [];

    if (filters.components?.length) {
      parts.push(
        `${filters.components.length} composant${filters.components.length > 1 ? 's' : ''}`
      );
    }
    if (filters.fixVersions?.length) {
      parts.push(
        `${filters.fixVersions.length} version${filters.fixVersions.length > 1 ? 's' : ''}`
      );
    }
    if (filters.issueTypes?.length) {
      parts.push(
        `${filters.issueTypes.length} type${filters.issueTypes.length > 1 ? 's' : ''}`
      );
    }
    if (filters.statuses?.length) {
      parts.push(
        `${filters.statuses.length} statut${filters.statuses.length > 1 ? 's' : ''}`
      );
    }
    if (filters.assignees?.length) {
      parts.push(
        `${filters.assignees.length} assigné${filters.assignees.length > 1 ? 's' : ''}`
      );
    }
    if (filters.labels?.length) {
      parts.push(
        `${filters.labels.length} label${filters.labels.length > 1 ? 's' : ''}`
      );
    }
    if (filters.priorities?.length) {
      parts.push(
        `${filters.priorities.length} priorité${filters.priorities.length > 1 ? 's' : ''}`
      );
    }
    if (filters.dateRange) {
      parts.push('période personnalisée');
    }

    if (parts.length === 0) return 'Aucun filtre actif';
    if (parts.length === 1) return `Filtré par ${parts[0]}`;
    if (parts.length === 2) return `Filtré par ${parts[0]} et ${parts[1]}`;
    return `Filtré par ${parts.slice(0, -1).join(', ')} et ${parts[parts.length - 1]}`;
  }
}
