/**
 * Service de gestion TFS/Azure DevOps
 * Intégration unidirectionnelle Azure DevOps → TowerControl
 * Focus sur les Pull Requests comme tâches
 */

import { TfsPullRequest } from '@/lib/types';
import { prisma } from '@/services/core/database';
import { parseDate, formatDateForDisplay } from '@/lib/date-utils';
import { userPreferencesService } from '@/services/core/user-preferences';
import { tagsService } from '../../task-management/tags';
import { buildSyncUpdateData } from '../../task-management/readonly-fields';

export interface TfsConfig {
  enabled: boolean;
  organizationUrl?: string; // https://dev.azure.com/myorg
  projectName?: string; // Optionnel: pour filtrer un projet spécifique
  personalAccessToken?: string;
  repositories?: string[]; // Liste des repos à surveiller
  ignoredRepositories?: string[]; // Liste des repos à ignorer
  maxSyncPeriod?: '7d' | '30d' | '90d' | '180d' | '1y' | '2y' | '3y'; // Période maximale de synchronisation
}

export interface TfsSyncAction {
  type: 'created' | 'updated' | 'skipped' | 'deleted';
  pullRequestId: number;
  prTitle: string;
  reason?: string;
  changes?: string[];
}

// Types génériques pour compatibilité avec d'autres services
export interface SyncAction {
  type: 'created' | 'updated' | 'skipped' | 'deleted';
  itemId: string | number;
  title: string;
  message?: string;
}

export interface SyncResult {
  success: boolean;
  totalItems: number;
  actions: SyncAction[];
  errors: string[];
  stats: {
    created: number;
    updated: number;
    skipped: number;
    deleted: number;
  };
}

export interface TfsSyncResult {
  success: boolean;
  totalPullRequests: number;
  pullRequestsCreated: number;
  pullRequestsUpdated: number;
  pullRequestsSkipped: number;
  pullRequestsDeleted: number;
  errors: string[];
  actions: TfsSyncAction[];
}

export class TfsService {
  readonly config: TfsConfig;

  constructor(config: TfsConfig) {
    this.config = config;
  }

  /**
   * Teste la connexion à Azure DevOps
   */
  async testConnection(): Promise<boolean> {
    try {
      // Tester avec l'endpoint des projets pour valider l'accès à l'organisation
      const response = await this.makeApiRequest(
        '/_apis/projects?api-version=6.0&$top=1'
      );

      if (response.ok) {
        console.log('✓ Connexion TFS réussie et organisation accessible');
        return true;
      } else if (response.status === 401) {
        console.error(
          '❗️ Erreur TFS: Authentification échouée (token invalide)'
        );
        return false;
      } else if (response.status === 403) {
        console.error(
          '❗️ Erreur TFS: Accès refusé (permissions insuffisantes)'
        );
        return false;
      } else {
        console.error(
          `❗️ Erreur TFS: ${response.status} ${response.statusText}`
        );
        return false;
      }
    } catch (error) {
      console.error('❗️ Erreur connexion TFS:', error);
      return false;
    }
  }

  /**
   * Valide la configuration TFS
   */
  async validateConfig(): Promise<{ valid: boolean; error?: string }> {
    if (!this.config.enabled) {
      return { valid: false, error: 'TFS désactivé' };
    }
    if (!this.config.organizationUrl) {
      return { valid: false, error: "URL de l'organisation manquante" };
    }
    if (!this.config.personalAccessToken) {
      return { valid: false, error: "Token d'accès personnel manquant" };
    }

    // Tester la connexion pour validation complète
    const connectionOk = await this.testConnection();
    if (!connectionOk) {
      return {
        valid: false,
        error: 'Impossible de se connecter avec ces paramètres',
      };
    }

    return { valid: true };
  }

  /**
   * Valide l'existence d'un projet Azure DevOps
   */
  async validateProject(
    projectName: string
  ): Promise<{ exists: boolean; name?: string; error?: string }> {
    try {
      const response = await this.makeApiRequest(
        `/_apis/projects/${encodeURIComponent(projectName)}?api-version=6.0`
      );

      if (response.ok) {
        const projectData = await response.json();
        return {
          exists: true,
          name: projectData.name,
        };
      } else if (response.status === 404) {
        return {
          exists: false,
          error: `Projet "${projectName}" non trouvé`,
        };
      } else {
        const errorData = await response.json().catch(() => ({}));
        return {
          exists: false,
          error: errorData.message || `Erreur ${response.status}`,
        };
      }
    } catch (error) {
      console.error('❌ Erreur validation projet TFS:', error);
      return {
        exists: false,
        error: error instanceof Error ? error.message : 'Erreur de connexion',
      };
    }
  }

  /**
   * Récupère la liste des repositories d'un projet (ou de toute l'organisation si pas de projet spécifié)
   */
  async getRepositories(): Promise<
    Array<{ id: string; name: string; project?: string }>
  > {
    try {
      // Si un projet spécifique est configuré, récupérer uniquement ses repos
      let endpoint: string;
      if (this.config.projectName) {
        endpoint = `/_apis/git/repositories?api-version=6.0&$top=1000`;
      } else {
        // Récupérer tous les repositories de l'organisation
        endpoint = `/_apis/git/repositories?api-version=6.0&includeAllProjects=true&$top=1000`;
      }

      const response = await this.makeApiRequest(endpoint);

      if (!response.ok) {
        throw new Error(`Erreur API: ${response.status}`);
      }

      const data = await response.json();
      return (
        data.value?.map(
          (repo: { id: string; name: string; project?: { name: string } }) => ({
            id: repo.id,
            name: repo.name,
            project: repo.project?.name,
          })
        ) || []
      );
    } catch (error) {
      console.error('❗️ Erreur récupération repositories TFS:', error);
      return [];
    }
  }

  /**
   * Récupère toutes les Pull Requests assignées à l'utilisateur actuel dans l'organisation
   */
  async getMyPullRequests(): Promise<TfsPullRequest[]> {
    try {
      // Uniquement les PRs créées par l'utilisateur (simplifié)
      const createdPrs = await this.getPullRequestsByCreator();

      // Filtrer les PRs selon la configuration
      const filteredPrs = this.filterPullRequests(createdPrs);

      return filteredPrs;
    } catch (error) {
      console.error('❗️ Erreur récupération PRs utilisateur:', error);
      return [];
    }
  }

  /**
   * Récupère les PRs créées par l'utilisateur
   */
  private async getPullRequestsByCreator(): Promise<TfsPullRequest[]> {
    try {
      // Récupérer l'ID utilisateur réel pour le filtrage
      const currentUserId = await this.getCurrentUserId();
      if (!currentUserId) {
        console.error(
          "❌ Impossible de récupérer l'ID utilisateur pour filtrer les PRs"
        );
        return [];
      }

      console.log(
        `🎯 Recherche des PRs créées par l'utilisateur ID: ${currentUserId}`
      );

      const searchParams = new URLSearchParams({
        'api-version': '6.0',
        'searchCriteria.creatorId': currentUserId, // Utiliser l'ID réel au lieu de @me
        'searchCriteria.status': 'all', // Inclut active, completed, abandoned
        $top: '1000',
      });

      const url = `/_apis/git/pullrequests?${searchParams.toString()}`;
      const response = await this.makeApiRequest(url);

      if (!response.ok) {
        const errorText = await response.text();
        console.error('❌ Erreur API créateur:', response.status, errorText);
        throw new Error(
          `Erreur API créateur: ${response.status} - ${errorText}`
        );
      }

      const data = await response.json();

      const prs = data.value || [];
      return prs;
    } catch (error) {
      console.error('❗️ Erreur récupération PRs créateur:', error);
      return [];
    }
  }

  /**
   * Récupère l'ID de l'utilisateur courant
   */
  private async getCurrentUserId(): Promise<string | null> {
    try {
      // Essayer d'abord avec l'endpoint ConnectionData (plus fiable)
      const response = await this.makeApiRequest('/_apis/connectionData');

      if (response.ok) {
        const connectionData = await response.json();
        const userId = connectionData?.authenticatedUser?.id;
        if (userId) {
          console.log('✅ ID utilisateur récupéré via ConnectionData:', userId);
          return userId;
        }
      }

      console.error(
        "❌ Impossible de récupérer l'ID utilisateur par aucune méthode"
      );
      return null;
    } catch (error) {
      console.error('❌ Erreur récupération ID utilisateur:', error);
      return null;
    }
  }

  /**
   * Filtre les Pull Requests selon la configuration
   */
  private filterPullRequests(pullRequests: TfsPullRequest[]): TfsPullRequest[] {
    console.log('🗺 Configuration de filtrage:', {
      projectName: this.config.projectName,
      repositories: this.config.repositories,
      ignoredRepositories: this.config.ignoredRepositories,
    });

    // console.log(
    //   '📋 PRs avant filtrage:',
    //   pullRequests.map((pr) => ({
    //     id: pr.pullRequestId,
    //     title: pr.title,
    //     project: pr.repository.project.name,
    //     repository: pr.repository.name,
    //     status: pr.status,
    //     closedDate: pr.closedDate,
    //   }))
    // );

    let filtered = pullRequests;
    const initialCount = filtered.length;

    // 1. Filtrer par statut pertinent (exclure les abandoned, limiter les completed récentes)
    const beforeStatusFilter = filtered.length;
    filtered = this.filterByRelevantStatus(filtered);
    console.log(
      `📋 Filtrage statut pertinent: ${beforeStatusFilter} -> ${filtered.length}`
    );

    // 2. Filtrer par projet si spécifié
    if (this.config.projectName) {
      const beforeProjectFilter = filtered.length;
      filtered = filtered.filter(
        (pr) => pr.repository.project.name === this.config.projectName
      );
      console.log(
        `🎯 Filtrage projet "${this.config.projectName}": ${beforeProjectFilter} -> ${filtered.length}`
      );
    }

    // Filtrer par repositories autorisés
    if (this.config.repositories?.length) {
      const beforeRepoFilter = filtered.length;
      filtered = filtered.filter((pr) =>
        this.config.repositories!.includes(pr.repository.name)
      );
      console.log(
        `📋 Filtrage repositories autorisés ${JSON.stringify(this.config.repositories)}: ${beforeRepoFilter} -> ${filtered.length}`
      );
    }

    // Exclure les repositories ignorés
    if (this.config.ignoredRepositories?.length) {
      const beforeIgnoreFilter = filtered.length;
      filtered = filtered.filter(
        (pr) => !this.config.ignoredRepositories!.includes(pr.repository.name)
      );
      console.log(
        `❌ Exclusion repositories ignorés ${JSON.stringify(this.config.ignoredRepositories)}: ${beforeIgnoreFilter} -> ${filtered.length}`
      );
    }

    console.log(
      `🎟️ Résultat filtrage final: ${initialCount} -> ${filtered.length}`
    );
    // console.log(
    //   '📋 PRs après filtrage:',
    //   filtered.map((pr) => ({
    //     id: pr.pullRequestId,
    //     title: pr.title,
    //     project: pr.repository.project.name,
    //     repository: pr.repository.name,
    //     status: pr.status,
    //   }))
    // );

    return filtered;
  }

  /**
   * Filtre les PRs par statut pertinent
   * - Garde toutes les PRs actives créées dans la période configurée
   * - Garde les PRs completed récentes (moins de 30 jours)
   * - Exclut les PRs abandoned et rejected
   * - Exclut les PRs trop anciennes selon la configuration
   * - Exclut les PRs automatiques (Renovate, etc.)
   */
  private filterByRelevantStatus(
    pullRequests: TfsPullRequest[]
  ): TfsPullRequest[] {
    const now = new Date();
    const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);

    // Calculer la période maximale selon la configuration
    const maxSyncPeriod = this.config.maxSyncPeriod || '90d';
    const maxSyncPeriodMs = this.getMaxSyncPeriodMs(maxSyncPeriod);
    const maxSyncDate = new Date(now.getTime() - maxSyncPeriodMs);

    return pullRequests.filter((pr) => {
      // Exclure les PRs automatiques (Renovate, Dependabot, etc.)
      if (this.isAutomaticPR(pr)) {
        console.log(
          `🤖 PR ${pr.pullRequestId} (${pr.title}): PR automatique - EXCLUE`
        );
        return false;
      }

      // Filtrer par âge selon la configuration
      const createdDate = parseDate(pr.creationDate);
      if (createdDate < maxSyncDate) {
        console.log(
          `🗺 PR ${pr.pullRequestId} (${pr.title}): Trop ancienne (${formatDateForDisplay(createdDate)}, limite: ${maxSyncPeriod}) - EXCLUE`
        );
        return false;
      }

      switch (pr.status.toLowerCase()) {
        case 'active':
          // PRs actives dans la période configurée
          console.log(
            `✅ PR ${pr.pullRequestId} (${pr.title}): Active récente (${maxSyncPeriod}) - INCLUSE`
          );
          return true;

        case 'completed':
          // PRs completed récentes (moins de 30 jours)
          if (pr.closedDate) {
            const closedDate = parseDate(pr.closedDate);
            const isRecent = closedDate >= thirtyDaysAgo;
            return isRecent;
          } else {
            // Si pas de date de fermeture, on l'inclut par sécurité
            return true;
          }

        case 'abandoned':
          // PRs abandonnées ne sont pas pertinentes
          console.log(
            `❌ PR ${pr.pullRequestId} (${pr.title}): Abandonnée - EXCLUE`
          );
          return false;

        case 'rejected':
          // PRs rejetées ne sont pas pertinentes
          console.log(
            `❌ PR ${pr.pullRequestId} (${pr.title}): Rejetée - EXCLUE`
          );
          return false;

        default:
          // Statut inconnu, on l'inclut par précaution
          console.log(
            `⚠️ PR ${pr.pullRequestId} (${pr.title}): Statut inconnu "${pr.status}" - INCLUSE par précaution`
          );
          return true;
      }
    });
  }

  /**
   * Convertit une période de synchronisation en millisecondes
   */
  private getMaxSyncPeriodMs(period: string): number {
    switch (period) {
      case '7d':
        return 7 * 24 * 60 * 60 * 1000; // 7 jours
      case '30d':
        return 30 * 24 * 60 * 60 * 1000; // 30 jours
      case '90d':
        return 90 * 24 * 60 * 60 * 1000; // 90 jours
      case '180d':
        return 180 * 24 * 60 * 60 * 1000; // 180 jours
      case '1y':
        return 365 * 24 * 60 * 60 * 1000; // 1 an
      case '2y':
        return 2 * 365 * 24 * 60 * 60 * 1000; // 2 ans
      case '3y':
        return 3 * 365 * 24 * 60 * 60 * 1000; // 3 ans
      default:
        return 90 * 24 * 60 * 60 * 1000; // Par défaut 90 jours
    }
  }

  /**
   * Détermine si une PR est automatique (bot, renovate, dependabot, etc.)
   */
  private isAutomaticPR(pr: TfsPullRequest): boolean {
    // Patterns dans le titre
    const automaticTitlePatterns = [
      /configure renovate/i,
      /update dependency/i,
      /bump .+ from .+ to/i,
      /\[dependabot\]/i,
      /\[renovate\]/i,
      /automated pr/i,
      /auto.update/i,
      /security update/i,
    ];

    // Vérifier le titre
    for (const pattern of automaticTitlePatterns) {
      if (pattern.test(pr.title)) {
        return true;
      }
    }

    // Patterns dans la description
    const automaticDescPatterns = [
      /this pr was automatically created/i,
      /renovate bot/i,
      /dependabot/i,
      /automated dependency update/i,
    ];

    // Vérifier la description
    if (pr.description) {
      for (const pattern of automaticDescPatterns) {
        if (pattern.test(pr.description)) {
          return true;
        }
      }
    }

    // Vérifier l'auteur (noms de bots courants)
    const botAuthors = [
      'renovate[bot]',
      'dependabot[bot]',
      'dependabot',
      'renovate',
      'greenkeeper[bot]',
      'snyk-bot',
    ];

    const authorName = pr.createdBy.displayName?.toLowerCase() || '';
    for (const botName of botAuthors) {
      if (authorName.includes(botName.toLowerCase())) {
        return true;
      }
    }

    // Vérifier la branche source (patterns de bots)
    const automaticBranchPatterns = [
      /renovate\//i,
      /dependabot\//i,
      /update\/.+dependency/i,
      /bump\//i,
    ];

    const sourceBranch = pr.sourceRefName.replace('refs/heads/', '');
    for (const pattern of automaticBranchPatterns) {
      if (pattern.test(sourceBranch)) {
        return true;
      }
    }

    return false;
  }

  /**
   * Synchronise les Pull Requests avec les tâches locales
   */
  async syncTasks(userId: string): Promise<TfsSyncResult> {
    const result: TfsSyncResult = {
      success: true,
      totalPullRequests: 0,
      pullRequestsCreated: 0,
      pullRequestsUpdated: 0,
      pullRequestsSkipped: 0,
      pullRequestsDeleted: 0,
      actions: [],
      errors: [],
    };

    try {
      console.log('🔄 Début synchronisation TFS Pull Requests...');

      // S'assurer que le tag TFS existe
      await this.ensureTfsTagExists(userId);

      // Récupérer toutes les PRs assignées à l'utilisateur
      const allPullRequests = await this.getMyPullRequests();
      result.totalPullRequests = allPullRequests.length;

      if (allPullRequests.length === 0) {
        return result;
      }

      // Récupérer les IDs des PRs actuelles pour le nettoyage
      const currentPrIds = new Set(
        allPullRequests.map((pr) => pr.pullRequestId)
      );

      // Synchroniser chaque PR
      for (const pr of allPullRequests) {
        try {
          const syncAction = await this.syncSinglePullRequest(pr, userId);
          result.actions.push(syncAction);

          // Compter les actions
          if (syncAction.type === 'created') {
            result.pullRequestsCreated++;
          } else if (syncAction.type === 'updated') {
            result.pullRequestsUpdated++;
          } else {
            result.pullRequestsSkipped++;
          }
        } catch (error) {
          const errorMsg = `Erreur sync PR ${pr.pullRequestId}: ${error instanceof Error ? error.message : 'Erreur inconnue'}`;
          result.errors.push(errorMsg);
          console.error('❌', errorMsg);
        }
      }

      // Nettoyer les tâches TFS qui ne sont plus actives
      const deletedActions =
        await this.cleanupInactivePullRequests(currentPrIds);
      result.pullRequestsDeleted = deletedActions.length;
      result.actions.push(...deletedActions);

      console.log(`✅ Synchronisation TFS terminée:`, {
        créées: result.pullRequestsCreated,
        mises_a_jour: result.pullRequestsUpdated,
        ignorées: result.pullRequestsSkipped,
        supprimées: result.pullRequestsDeleted,
      });

      result.success = result.errors.length === 0;
    } catch (error) {
      result.success = false;
      const errorMsg =
        error instanceof Error ? error.message : 'Erreur inconnue';
      result.errors.push(errorMsg);
      console.error('❌ Erreur sync TFS:', errorMsg);
    }

    return result;
  }

  /**
   * Synchronise une Pull Request unique
   */
  private async syncSinglePullRequest(
    pr: TfsPullRequest,
    userId: string
  ): Promise<TfsSyncAction> {
    const pullRequestId = pr.pullRequestId;
    const sourceId = `tfs-pr-${pullRequestId}`;

    // Chercher la tâche existante
    const existingTask = await prisma.task.findFirst({
      where: { sourceId },
    });

    const taskData = this.mapPullRequestToTask(pr);

    if (!existingTask) {
      // Créer nouvelle tâche
      const newTask = await prisma.task.create({
        data: {
          ...taskData,
          sourceId,
          createdAt: new Date(),
          updatedAt: new Date(),
          ownerId: userId,
        },
      });

      // Assigner le tag TFS
      await this.assignTfsTag(newTask.id, userId);

      return {
        type: 'created',
        pullRequestId,
        prTitle: pr.title,
      };
    } else {
      // Utiliser la logique centralisée pour déterminer quels champs préserver
      const finalData = buildSyncUpdateData('tfs', existingTask, taskData);

      // Détecter les changements
      const changes: string[] = [];

      if (existingTask.title !== finalData.title) {
        changes.push(`Titre: ${existingTask.title} → ${finalData.title}`);
      }
      if (existingTask.status !== finalData.status) {
        changes.push(`Statut: ${existingTask.status} → ${finalData.status}`);
      }
      if (existingTask.description !== finalData.description) {
        changes.push('Description modifiée');
      }
      if (existingTask.priority !== finalData.priority) {
        changes.push(
          `Priorité: ${existingTask.priority} → ${finalData.priority}`
        );
      }
      if (
        (existingTask.dueDate?.getTime() || null) !==
        (finalData.dueDate?.getTime() || null)
      ) {
        const oldDate = existingTask.dueDate
          ? formatDateForDisplay(existingTask.dueDate)
          : 'Aucune';
        const newDate = finalData.dueDate
          ? formatDateForDisplay(finalData.dueDate)
          : 'Aucune';
        changes.push(`Échéance: ${oldDate} → ${newDate}`);
      }
      if (existingTask.assignee !== taskData.assignee) {
        changes.push(
          `Assigné: ${existingTask.assignee} → ${taskData.assignee}`
        );
      }

      if (changes.length === 0) {
        // S'assurer que le tag TFS est assigné (pour les anciennes tâches)
        await this.assignTfsTag(existingTask.id, userId);

        return {
          type: 'skipped',
          pullRequestId,
          prTitle: pr.title,
          reason: 'Aucun changement détecté',
        };
      }

      // Mettre à jour la tâche avec les données finales déterminées par la logique centralisée
      await prisma.task.update({
        where: { id: existingTask.id },
        data: {
          ...finalData,
          tfsProject: taskData.tfsProject,
          tfsPullRequestId: taskData.tfsPullRequestId,
          tfsRepository: taskData.tfsRepository,
          tfsSourceBranch: taskData.tfsSourceBranch,
          tfsTargetBranch: taskData.tfsTargetBranch,
          assignee: taskData.assignee,
          updatedAt: new Date(),
        },
      });

      return {
        type: 'updated',
        pullRequestId,
        prTitle: pr.title,
        changes,
      };
    }
  }

  /**
   * Détermine quels champs sont en lecture seule pour une tâche TFS
   * Ces champs sont ceux qui sont écrasés par la synchronisation TFS
   * @deprecated Utiliser getReadonlyFieldsForTask() depuis readonly-fields.ts à la place
   */
  async getReadonlyFields(taskId: string): Promise<string[]> {
    try {
      const task = await prisma.task.findUnique({
        where: { id: taskId },
        select: {
          source: true,
          status: true,
        },
      });

      // Si ce n'est pas une tâche TFS, aucun champ n'est en lecture seule
      if (!task || task.source !== 'tfs') {
        return [];
      }

      // Utiliser la logique centralisée
      const { getReadonlyFieldsForTask } = await import(
        '../../task-management/readonly-fields'
      );
      return getReadonlyFieldsForTask(
        'tfs',
        task.status as
          | 'backlog'
          | 'todo'
          | 'in_progress'
          | 'done'
          | 'cancelled'
          | 'archived'
      );
    } catch (error) {
      console.error(
        'Erreur lors de la détermination des champs readonly:',
        error
      );
      return [];
    }
  }

  /**
   * S'assure que le tag TFS existe
   */
  private async ensureTfsTagExists(userId: string): Promise<void> {
    try {
      // Utiliser le service tags pour créer ou récupérer le tag
      await tagsService.ensureTagsExist(['🧑‍💻 TFS'], userId);
      console.log('✅ Tag TFS créé/récupéré');
    } catch (error) {
      console.warn('Erreur création tag TFS:', error);
    }
  }

  /**
   * Assigne automatiquement le tag "TFS" aux tâches importées
   */
  private async assignTfsTag(taskId: string, userId: string): Promise<void> {
    try {
      // Utiliser le service tags pour créer ou récupérer le tag
      const tags = await tagsService.ensureTagsExist(['🧑‍💻 TFS'], userId);
      const tfsTag = tags[0];

      // Vérifier si la relation existe déjà
      const existingRelation = await prisma.taskTag.findFirst({
        where: { taskId, tagId: tfsTag.id },
      });

      if (!existingRelation) {
        await prisma.taskTag.create({
          data: { taskId, tagId: tfsTag.id },
        });
      }
    } catch (error) {
      console.error('❌ Erreur assignation tag TFS:', error);
      // Ne pas faire échouer la sync pour un problème de tag
    }
  }

  /**
   * Mappe une Pull Request TFS vers le format Task
   */
  private mapPullRequestToTask(pr: TfsPullRequest) {
    const status = this.mapTfsStatusToInternal(pr.status);
    const sourceBranch = pr.sourceRefName.replace('refs/heads/', '');
    const targetBranch = pr.targetRefName.replace('refs/heads/', '');

    return {
      title: `PR: ${pr.title}`,
      description: this.formatPullRequestDescription(pr),
      status,
      priority: this.determinePrPriority(pr),
      source: 'tfs' as const,
      dueDate: null,
      completedAt:
        pr.status === 'completed' && pr.closedDate
          ? parseDate(pr.closedDate)
          : null,

      // Métadonnées TFS
      tfsProject: pr.repository.project.name,
      tfsPullRequestId: pr.pullRequestId,
      tfsRepository: pr.repository.name,
      tfsSourceBranch: sourceBranch,
      tfsTargetBranch: targetBranch,
      assignee: pr.createdBy.displayName,
    };
  }

  /**
   * Formate la description d'une Pull Request
   */
  private formatPullRequestDescription(pr: TfsPullRequest): string {
    const parts = [];

    if (pr.description) {
      parts.push(pr.description);
    }

    parts.push(`**Repository:** ${pr.repository.name}`);
    parts.push(
      `**Branch:** ${pr.sourceRefName.replace('refs/heads/', '')} → ${pr.targetRefName.replace('refs/heads/', '')}`
    );
    parts.push(`**Auteur:** ${pr.createdBy.displayName}`);
    parts.push(
      `**Créé le:** ${formatDateForDisplay(parseDate(pr.creationDate))}`
    );

    if (pr.reviewers && pr.reviewers.length > 0) {
      const reviewersInfo = pr.reviewers.map((r) => {
        let status = '';
        switch (r.vote) {
          case 10:
            status = '✅ Approuvé avec suggestions';
            break;
          case 5:
            status = '✅ Approuvé';
            break;
          case -5:
            status = "⏳ En attente de l'auteur";
            break;
          case -10:
            status = '❌ Rejeté';
            break;
          default:
            status = '⏳ Pas de vote';
        }
        return `${r.displayName}: ${status}`;
      });
      parts.push(`**Reviewers:**\n${reviewersInfo.join('\n')}`);
    }

    if (pr.isDraft) {
      parts.push('**🚧 Draft**');
    }

    return parts.join('\n\n');
  }

  /**
   * Mappe les statuts TFS vers les statuts internes
   */
  private mapTfsStatusToInternal(tfsStatus: string): string {
    switch (tfsStatus.toLowerCase()) {
      case 'active':
        return 'in_progress';
      case 'completed':
        return 'done';
      case 'abandoned':
        return 'cancelled';
      default:
        return 'todo';
    }
  }

  /**
   * Détermine la priorité d'une PR basée sur divers critères
   */
  private determinePrPriority(pr: TfsPullRequest): string {
    // PR en Draft = Low
    if (pr.isDraft) return 'low';

    // PR avec des conflits = High
    if (pr.mergeStatus === 'conflicts' || pr.mergeStatus === 'failed')
      return 'high';

    // PR vers main/master = Medium par défaut
    const targetBranch = pr.targetRefName.replace('refs/heads/', '');
    if (['main', 'master', 'production'].includes(targetBranch))
      return 'medium';

    // Défaut
    return 'low';
  }

  /**
   * Nettoie les tâches TFS qui ne correspondent plus aux PRs actives
   * Ne supprime PAS les tâches déjà terminées (done/archived) pour garder l'historique
   */
  private async cleanupInactivePullRequests(
    currentPrIds: Set<number>
  ): Promise<TfsSyncAction[]> {
    const deletedActions: TfsSyncAction[] = [];

    try {
      console.log('🧹 Nettoyage des tâches TFS inactives...');

      // Récupérer toutes les tâches TFS existantes
      const existingTfsTasks = await prisma.task.findMany({
        where: { source: 'tfs' },
        select: {
          id: true,
          sourceId: true,
          tfsPullRequestId: true,
          title: true,
          status: true,
        },
      });

      // Identifier les tâches à supprimer
      // MAIS on exclut les tâches déjà terminées (done/archived) car elles ont été complétées
      const tasksToDelete = existingTfsTasks.filter((task) => {
        const prId = task.tfsPullRequestId;
        if (!prId) {
          return true;
        }

        // Si la PR est toujours active, on la garde
        if (currentPrIds.has(prId)) {
          return false;
        }

        // Si la tâche est déjà terminée (done/archived), on la garde en base pour l'historique
        if (task.status === 'done' || task.status === 'archived') {
          console.log(
            `✅ PR ${prId} terminée - conservée en base malgré absence dans TFS`
          );
          return false;
        }

        // Sinon, c'est une tâche non terminée qui n'est plus active → suppression
        return true;
      });

      // Supprimer les tâches obsolètes
      for (const task of tasksToDelete) {
        try {
          await prisma.task.delete({ where: { id: task.id } });

          deletedActions.push({
            type: 'deleted',
            pullRequestId: task.tfsPullRequestId || 0,
            prTitle: task.title || `Tâche ${task.id}`,
            reason: 'Pull Request plus active ou supprimée',
          });
        } catch (error) {
          console.error(`❌ Erreur suppression tâche ${task.id}:`, error);
          // Continue avec les autres tâches
        }
      }

      if (tasksToDelete.length > 0) {
        console.log(
          `✨ ${tasksToDelete.length} tâches TFS obsolètes supprimées`
        );
      }
    } catch (error) {
      console.error('❌ Erreur nettoyage tâches TFS:', error);
    }

    return deletedActions;
  }

  /**
   * Supprime toutes les tâches TFS de la base de données locale
   */
  async deleteAllTasks(): Promise<{
    success: boolean;
    deletedCount: number;
    error?: string;
  }> {
    try {
      // Récupérer toutes les tâches TFS
      const tfsTasks = await prisma.task.findMany({
        where: { source: 'tfs' },
        select: { id: true, title: true },
      });

      if (tfsTasks.length === 0) {
        return {
          success: true,
          deletedCount: 0,
        };
      }

      // Supprimer toutes les tâches TFS en une seule opération
      const deleteResult = await prisma.task.deleteMany({
        where: { source: 'tfs' },
      });

      console.log(`✅ ${deleteResult.count} tâches TFS supprimées avec succès`);

      return {
        success: true,
        deletedCount: deleteResult.count,
      };
    } catch (error) {
      console.error('❌ Erreur suppression tâches TFS:', error);
      return {
        success: false,
        deletedCount: 0,
        error: error instanceof Error ? error.message : 'Erreur inconnue',
      };
    }
  }

  /**
   * Récupère les métadonnées du projet (repositories, branches, etc.)
   */
  async getMetadata(): Promise<{
    repositories: Array<{ id: string; name: string }>;
  }> {
    const repositories = await this.getRepositories();
    return { repositories };
  }

  /**
   * Effectue une requête vers l'API Azure DevOps
   */
  private async makeApiRequest(endpoint: string): Promise<Response> {
    if (!this.config.organizationUrl || !this.config.personalAccessToken) {
      throw new Error('Configuration TFS manquante');
    }

    // Si l'endpoint commence par /_apis, c'est un endpoint organisation
    // Sinon, on peut inclure le projet si spécifié
    let url: string;
    if (endpoint.startsWith('/_apis')) {
      url = `${this.config.organizationUrl}${endpoint}`;
    } else {
      // Pour compatibilité avec d'autres endpoints
      const project = this.config.projectName
        ? `/${this.config.projectName}`
        : '';
      url = `${this.config.organizationUrl}${project}${endpoint}`;
    }

    const headers: Record<string, string> = {
      Authorization: `Basic ${Buffer.from(`:${this.config.personalAccessToken}`).toString('base64')}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    };

    // console.log('🌐 Requête API Azure DevOps:', {
    //   url,
    //   method: 'GET',
    //   headers: {
    //     ...headers,
    //     'Authorization': 'Basic [MASQUÉ]' // Masquer le token pour la sécurité
    //   }
    // });

    const response = await fetch(url, { headers });

    // console.log('🔄 Réponse brute Azure DevOps:', {
    //   status: response.status,
    //   statusText: response.statusText,
    //   url: response.url,
    //   headers: Object.fromEntries(response.headers.entries())
    // });

    return response;
  }
}

/**
 * Instance TFS préconfigurée avec les préférences utilisateur
 */
class TfsServiceInstance extends TfsService {
  constructor() {
    super({ enabled: false }); // Config vide par défaut
  }

  private async getConfig(userId?: string): Promise<TfsConfig> {
    const targetUserId = userId || 'default';
    const userConfig = await userPreferencesService.getTfsConfig(targetUserId);
    return userConfig;
  }

  async testConnection(userId?: string): Promise<boolean> {
    const config = await this.getConfig(userId);
    if (
      !config.enabled ||
      !config.organizationUrl ||
      !config.personalAccessToken
    ) {
      return false;
    }

    const service = new TfsService(config);
    return service.testConnection();
  }

  async validateConfig(
    userId?: string
  ): Promise<{ valid: boolean; error?: string }> {
    const config = await this.getConfig(userId);
    const service = new TfsService(config);
    return service.validateConfig();
  }

  async syncTasks(userId: string): Promise<TfsSyncResult> {
    const config = await this.getConfig(userId);
    const service = new TfsService(config);
    return service.syncTasks(userId);
  }

  async deleteAllTasks(): Promise<{
    success: boolean;
    deletedCount: number;
    error?: string;
  }> {
    const config = await this.getConfig();
    const service = new TfsService(config);
    return service.deleteAllTasks();
  }

  async getMetadata(): Promise<{
    repositories: Array<{ id: string; name: string }>;
  }> {
    const config = await this.getConfig();
    const service = new TfsService(config);
    return service.getMetadata();
  }

  async validateProject(
    projectName: string
  ): Promise<{ exists: boolean; name?: string; error?: string }> {
    const config = await this.getConfig();
    const service = new TfsService(config);
    return service.validateProject(projectName);
  }

  reset(): void {
    // Pas besoin de reset, la config est récupérée à chaque fois
  }
}

/**
 * Service TFS préconfiguré avec récupération automatique des préférences
 */
export const tfsService = new TfsServiceInstance();
