/**
 * Service pour gérer les opérations liées à la liste de pistes
 * Récupération, pagination, filtres, tri
 */

import { apiClient } from '@/services/api/client';
import axios, { AxiosError } from 'axios';
import type { Track } from '../../player/types';
import type { TrackFilterOptions, TrackSortOptions } from '../types';

/**
 * Options de pagination
 */
export interface PaginationOptions {
  page: number;
  limit: number;
}

/**
 * Réponse paginée
 */
export interface PaginatedResponse<T> {
  data: T[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
}

/**
 * Options pour récupérer les pistes
 */
export interface GetTracksOptions {
  pagination?: PaginationOptions;
  filters?: TrackFilterOptions;
  sort?: TrackSortOptions;
  search?: string;
}

/**
 * Réponse de l'API pour les pistes
 */
export interface TracksResponse {
  tracks: Track[];
  total: number;
  page?: number;
  limit?: number;
  totalPages?: number;
}

/**
 * Erreur API
 */
export interface ApiError {
  message: string;
  code?: string;
  details?: Record<string, unknown>;
}

/**
 * Gère les erreurs API
 */
function handleApiError(error: unknown): never {
  if (axios.isAxiosError(error)) {
    const axiosError = error as AxiosError<ApiError>;
    const message =
      axiosError.response?.data?.message ||
      axiosError.message ||
      'Une erreur est survenue lors de la récupération des pistes';
    throw new Error(message);
  }
  throw error instanceof Error ? error : new Error('Une erreur inconnue est survenue');
}

/**
 * Récupère les pistes avec pagination, filtres et tri
 */
export async function getTracks(options: GetTracksOptions = {}): Promise<PaginatedResponse<Track>> {
  try {
    const { pagination, filters, sort, search } = options;

    // Construire les paramètres de requête
    const params = new URLSearchParams();

    // Pagination
    if (pagination) {
      params.append('page', pagination.page.toString());
      params.append('limit', pagination.limit.toString());
    }

    // Filtres
    if (filters) {
      if (filters.genre) {
        params.append('genre', filters.genre);
      }
      if (filters.artist) {
        params.append('artist', filters.artist);
      }
      if (filters.album) {
        params.append('album', filters.album);
      }
      if (filters.year) {
        params.append('year', filters.year.toString());
      }
      if (filters.minDuration) {
        params.append('min_duration', filters.minDuration.toString());
      }
      if (filters.maxDuration) {
        params.append('max_duration', filters.maxDuration.toString());
      }
    }

    // Tri
    if (sort) {
      params.append('sort_by', sort.field);
      params.append('sort_order', sort.order);
    }

    // Recherche
    if (search) {
      params.append('search', search);
    }

    const response = await apiClient.get<TracksResponse>(`/tracks?${params.toString()}`);

    const tracks = response.data.tracks || [];
    const total = response.data.total || tracks.length;
    const page = response.data.page || pagination?.page || 1;
    const limit = response.data.limit || pagination?.limit || tracks.length;
    const totalPages = response.data.totalPages || Math.ceil(total / limit);

    return {
      data: tracks,
      total,
      page,
      limit,
      totalPages,
    };
  } catch (error) {
    return handleApiError(error);
  }
}

/**
 * Récupère une piste par son ID
 */
export async function getTrackById(id: number): Promise<Track> {
  try {
    const response = await apiClient.get<Track>(`/tracks/${id}`);
    return response.data;
  } catch (error) {
    return handleApiError(error);
  }
}

/**
 * Récupère les pistes par artiste
 */
export async function getTracksByArtist(
  artist: string,
  options: Omit<GetTracksOptions, 'filters'> = {}
): Promise<PaginatedResponse<Track>> {
  return getTracks({
    ...options,
    filters: { ...options.filters, artist },
  });
}

/**
 * Récupère les pistes par album
 */
export async function getTracksByAlbum(
  album: string,
  options: Omit<GetTracksOptions, 'filters'> = {}
): Promise<PaginatedResponse<Track>> {
  return getTracks({
    ...options,
    filters: { ...options.filters, album },
  });
}

/**
 * Récupère les pistes par genre
 */
export async function getTracksByGenre(
  genre: string,
  options: Omit<GetTracksOptions, 'filters'> = {}
): Promise<PaginatedResponse<Track>> {
  return getTracks({
    ...options,
    filters: { ...options.filters, genre },
  });
}

/**
 * Recherche des pistes
 */
export async function searchTracks(
  query: string,
  options: Omit<GetTracksOptions, 'search'> = {}
): Promise<PaginatedResponse<Track>> {
  return getTracks({
    ...options,
    search: query,
  });
}

