import { apiClient } from '@/services/api/client';
import { Track } from '../types/track';
import { AxiosError } from 'axios';

/**
 * Track Share Service
 * T0309: Service frontend pour gérer le partage de tracks
 */

/**
 * Classe d'erreur personnalisée pour le partage de tracks
 */
export class TrackShareError extends Error {
  constructor(
    message: string,
    public code:
      | 'VALIDATION'
      | 'NETWORK'
      | 'SERVER'
      | 'FORBIDDEN'
      | 'NOT_FOUND'
      | 'UNKNOWN',
    public retryable: boolean = false,
    public originalError?: unknown,
  ) {
    super(message);
    this.name = 'TrackShareError';
  }
}

/**
 * Interface pour un lien de partage de track
 */
export interface TrackShare {
  id: string;
  track_id: string;
  user_id: string;
  share_token: string;
  permissions: string;
  expires_at?: string;
  access_count: number;
  created_at: string;
  updated_at: string;
}

/**
 * Interface pour la requête de création d'un lien de partage
 */
export interface CreateShareRequest {
  permissions: string;
  expires_at?: string;
}

/**
 * Interface pour la réponse de récupération d'un track partagé
 */
export interface SharedTrackResponse {
  track: Track;
  share: TrackShare;
}

/**
 * Crée un lien de partage pour un track
 * @param trackId ID du track à partager
 * @param data Données du partage (permissions, expiration)
 * @returns Le lien de partage créé
 * @throws TrackShareError si la requête échoue
 */
export async function createShare(
  trackId: string,
  data: CreateShareRequest,
): Promise<TrackShare> {
  try {
    const response = await apiClient.post<{ share: TrackShare }>(
      `/tracks/${trackId}/share`,
      data,
    );
    return response.data.share;
  } catch (error) {
    if (error instanceof AxiosError) {
      if (error.response?.status === 400) {
        const errorMessage = error.response?.data?.error || 'Données invalides';
        throw new TrackShareError(errorMessage, 'VALIDATION', false, error);
      }
      if (error.response?.status === 401) {
        throw new TrackShareError(
          'Non autorisé: Veuillez vous connecter pour créer un lien de partage',
          'VALIDATION',
          false,
          error,
        );
      }
      if (error.response?.status === 403) {
        throw new TrackShareError(
          'Accès refusé: Vous ne pouvez partager que vos propres tracks',
          'FORBIDDEN',
          false,
          error,
        );
      }
      if (error.response?.status === 404) {
        throw new TrackShareError(
          'Track introuvable',
          'NOT_FOUND',
          false,
          error,
        );
      }
      if (error.response?.status === 500) {
        throw new TrackShareError(
          'Erreur serveur: Impossible de créer le lien de partage. Veuillez réessayer plus tard.',
          'SERVER',
          true,
          error,
        );
      }
      // Erreurs réseau
      if (
        error.code === 'ECONNABORTED' ||
        error.code === 'ETIMEDOUT' ||
        !error.response
      ) {
        throw new TrackShareError(
          'Erreur réseau: Impossible de se connecter au serveur. Veuillez vérifier votre connexion.',
          'NETWORK',
          true,
          error,
        );
      }
      const errorMessage =
        error.response?.data?.error ||
        error.message ||
        'Échec de la création du lien de partage';
      throw new TrackShareError(errorMessage, 'UNKNOWN', false, error);
    }
    // Si c'est déjà une TrackShareError, la relancer
    if (error instanceof TrackShareError) {
      throw error;
    }
    // Erreur inconnue
    throw new TrackShareError(
      'Erreur inconnue lors de la création du lien de partage',
      'UNKNOWN',
      false,
      error,
    );
  }
}

/**
 * Récupère un track partagé via son token
 * @param token Token de partage
 * @returns Le track et les informations de partage
 * @throws TrackShareError si la requête échoue
 */
export async function getSharedTrack(
  token: string,
): Promise<SharedTrackResponse> {
  try {
    const response = await apiClient.get<SharedTrackResponse>(
      `/tracks/shared/${token}`,
    );
    return response.data;
  } catch (error) {
    if (error instanceof AxiosError) {
      if (error.response?.status === 400) {
        const errorMessage = error.response?.data?.error || 'Token invalide';
        throw new TrackShareError(errorMessage, 'VALIDATION', false, error);
      }
      if (error.response?.status === 403) {
        const errorMessage =
          error.response?.data?.error || 'Lien de partage expiré';
        throw new TrackShareError(errorMessage, 'FORBIDDEN', false, error);
      }
      if (error.response?.status === 404) {
        throw new TrackShareError(
          'Lien de partage invalide ou introuvable',
          'NOT_FOUND',
          false,
          error,
        );
      }
      if (error.response?.status === 500) {
        throw new TrackShareError(
          'Erreur serveur: Impossible de récupérer le track partagé. Veuillez réessayer plus tard.',
          'SERVER',
          true,
          error,
        );
      }
      // Erreurs réseau
      if (
        error.code === 'ECONNABORTED' ||
        error.code === 'ETIMEDOUT' ||
        !error.response
      ) {
        throw new TrackShareError(
          'Erreur réseau: Impossible de se connecter au serveur. Veuillez vérifier votre connexion.',
          'NETWORK',
          true,
          error,
        );
      }
      const errorMessage =
        error.response?.data?.error ||
        error.message ||
        'Échec de la récupération du track partagé';
      throw new TrackShareError(errorMessage, 'UNKNOWN', false, error);
    }
    // Si c'est déjà une TrackShareError, la relancer
    if (error instanceof TrackShareError) {
      throw error;
    }
    // Erreur inconnue
    throw new TrackShareError(
      'Erreur inconnue lors de la récupération du track partagé',
      'UNKNOWN',
      false,
      error,
    );
  }
}

/**
 * Révoque un lien de partage
 * @param shareId ID du lien de partage à révoquer
 * @throws TrackShareError si la requête échoue
 */
export async function revokeShare(shareId: string): Promise<void> {
  try {
    await apiClient.delete(`/tracks/shares/${shareId}`);
  } catch (error) {
    if (error instanceof AxiosError) {
      if (error.response?.status === 401) {
        throw new TrackShareError(
          'Non autorisé: Veuillez vous connecter pour révoquer un lien de partage',
          'VALIDATION',
          false,
          error,
        );
      }
      if (error.response?.status === 403) {
        throw new TrackShareError(
          'Accès refusé: Vous ne pouvez révoquer que vos propres liens de partage',
          'FORBIDDEN',
          false,
          error,
        );
      }
      if (error.response?.status === 404) {
        throw new TrackShareError(
          'Lien de partage introuvable',
          'NOT_FOUND',
          false,
          error,
        );
      }
      if (error.response?.status === 500) {
        throw new TrackShareError(
          'Erreur serveur: Impossible de révoquer le lien de partage. Veuillez réessayer plus tard.',
          'SERVER',
          true,
          error,
        );
      }
      // Erreurs réseau
      if (
        error.code === 'ECONNABORTED' ||
        error.code === 'ETIMEDOUT' ||
        !error.response
      ) {
        throw new TrackShareError(
          'Erreur réseau: Impossible de se connecter au serveur. Veuillez vérifier votre connexion.',
          'NETWORK',
          true,
          error,
        );
      }
      const errorMessage =
        error.response?.data?.error ||
        error.message ||
        'Échec de la révocation du lien de partage';
      throw new TrackShareError(errorMessage, 'UNKNOWN', false, error);
    }
    // Si c'est déjà une TrackShareError, la relancer
    if (error instanceof TrackShareError) {
      throw error;
    }
    // Erreur inconnue
    throw new TrackShareError(
      'Erreur inconnue lors de la révocation du lien de partage',
      'UNKNOWN',
      false,
      error,
    );
  }
}
