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

/**
 * Track Search Service
 * T0304: Service frontend pour recherche avancée de tracks avec support de tous les filtres et options de tri
 */

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

/**
 * Interface pour les paramètres de recherche de tracks
 */
export interface TrackSearchParams {
  query?: string;
  tags?: string[];
  tagMode?: 'AND' | 'OR';
  minDuration?: number;
  maxDuration?: number;
  minBPM?: number;
  maxBPM?: number;
  genre?: string;
  format?: string;
  minDate?: string;
  maxDate?: string;
  page?: number;
  limit?: number;
  sortBy?:
    | 'popularity'
    | 'play_count'
    | 'comment_count'
    | 'title'
    | 'created_at'
    | 'duration'
    | 'bpm'
    | 'artist'
    | 'updated_at'
    | 'like_count';
  sortOrder?: 'asc' | 'desc';
}

/**
 * Interface pour la réponse de recherche de tracks
 */
export interface TrackSearchResponse {
  tracks: Track[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    total_pages: number;
  };
}

/**
 * Construit les paramètres de requête URL à partir des paramètres de recherche
 * @param params Paramètres de recherche
 * @returns URLSearchParams
 */
function buildSearchQuery(params: TrackSearchParams): URLSearchParams {
  const queryParams = new URLSearchParams();

  if (params.query) {
    queryParams.append('q', params.query);
  }

  if (params.tags && params.tags.length > 0) {
    queryParams.append('tags', params.tags.join(','));
  }

  if (params.tagMode) {
    queryParams.append('tag_mode', params.tagMode);
  }

  if (params.minDuration !== undefined) {
    queryParams.append('min_duration', params.minDuration.toString());
  }

  if (params.maxDuration !== undefined) {
    queryParams.append('max_duration', params.maxDuration.toString());
  }

  if (params.minBPM !== undefined) {
    queryParams.append('min_bpm', params.minBPM.toString());
  }

  if (params.maxBPM !== undefined) {
    queryParams.append('max_bpm', params.maxBPM.toString());
  }

  if (params.genre) {
    queryParams.append('genre', params.genre);
  }

  if (params.format) {
    queryParams.append('format', params.format);
  }

  if (params.minDate) {
    queryParams.append('min_date', params.minDate);
  }

  if (params.maxDate) {
    queryParams.append('max_date', params.maxDate);
  }

  if (params.page !== undefined) {
    queryParams.append('page', params.page.toString());
  }

  if (params.limit !== undefined) {
    queryParams.append('limit', params.limit.toString());
  }

  if (params.sortBy) {
    queryParams.append('sort_by', params.sortBy);
  }

  if (params.sortOrder) {
    queryParams.append('sort_order', params.sortOrder);
  }

  return queryParams;
}

/**
 * Recherche des tracks avec filtres avancés et options de tri
 * @param params Paramètres de recherche
 * @returns La réponse de recherche avec les tracks et la pagination
 * @throws TrackSearchError si la requête échoue
 */
export async function searchTracks(
  params: TrackSearchParams = {},
): Promise<TrackSearchResponse> {
  try {
    const queryParams = buildSearchQuery(params);
    const queryString = queryParams.toString();
    const url = `/tracks/search${queryString ? `?${queryString}` : ''}`;

    const response = await apiClient.get<TrackSearchResponse>(url);
    return response.data;
  } catch (error) {
    if (error instanceof AxiosError) {
      if (error.response?.status === 400) {
        const errorMessage =
          error.response?.data?.error || 'Paramètres de recherche invalides';
        throw new TrackSearchError(errorMessage, 'VALIDATION', false, error);
      }
      if (error.response?.status === 500) {
        throw new TrackSearchError(
          "Erreur serveur: Impossible d'effectuer la recherche. Veuillez réessayer plus tard.",
          'SERVER',
          true,
          error,
        );
      }
      // Erreurs réseau
      if (
        error.code === 'ECONNABORTED' ||
        error.code === 'ETIMEDOUT' ||
        !error.response
      ) {
        throw new TrackSearchError(
          '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 recherche de tracks';
      throw new TrackSearchError(errorMessage, 'UNKNOWN', false, error);
    }
    // Si c'est déjà une TrackSearchError, la relancer
    if (error instanceof TrackSearchError) {
      throw error;
    }
    // Erreur inconnue
    throw new TrackSearchError(
      'Erreur inconnue lors de la recherche',
      'UNKNOWN',
      false,
      error,
    );
  }
}
