/**
 * Hook useTrackList
 * Gère l'état et la logique de la liste de pistes avec intégration du service API
 */

import { useState, useEffect, useCallback, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import { getTracks } from '../services/trackListService';
import type { Track } from '../../player/types';
import type {
  TrackListState,
  TrackFilterOptions,
  TrackSortOptions,
  TrackSortOption,
  SortOrder,
  TrackListDisplayMode,
} from '../types';
import type { PaginationOptions, PaginatedResponse } from '../services/trackListService';

export interface UseTrackListOptions {
  initialTracks?: Track[];
  initialDisplayMode?: TrackListDisplayMode;
  initialSortOptions?: TrackSortOptions;
  initialFilterOptions?: TrackFilterOptions;
  initialPagination?: PaginationOptions;
  useService?: boolean; // Si true, utilise le service API, sinon tri/filtrage côté client
  searchQuery?: string;
  autoLoad?: boolean; // Si true, charge automatiquement les tracks au montage
  persistFilters?: boolean; // Si true, persiste les filtres dans localStorage
  persistSort?: boolean; // Si true, persiste le tri dans localStorage
  syncUrlParams?: boolean; // Si true, synchronise avec les URL params
  storageKeyPrefix?: string; // Préfixe pour les clés localStorage
}

export interface UseTrackListReturn extends TrackListState {
  // État de pagination
  pagination: PaginationOptions;
  total: number;
  totalPages: number;
  
  // Actions
  setTracks: (tracks: Track[]) => void;
  setDisplayMode: (mode: TrackListDisplayMode) => void;
  setSortField: (field: TrackSortOption) => void;
  setSortOrder: (order: SortOrder) => void;
  setFilterOptions: (options: TrackFilterOptions) => void;
  clearFilters: () => void;
  setPagination: (pagination: PaginationOptions) => void;
  setPage: (page: number) => void;
  setLimit: (limit: number) => void;
  setSearchQuery: (query: string) => void;
  
  // Actions CRUD
  addTrack: (track: Track) => void;
  removeTrack: (trackId: number) => void;
  updateTrack: (track: Track) => void;
  
  // Actions de chargement
  loadTracks: () => Promise<void>;
  refreshTracks: () => Promise<void>;
}

/**
 * Hook pour gérer une liste de pistes avec tri, filtrage et pagination
 * Peut utiliser le service API ou faire le tri/filtrage côté client
 */
export function useTrackList(options: UseTrackListOptions = {}): UseTrackListReturn {
  const {
    initialTracks = [],
    initialDisplayMode = 'list',
    initialSortOptions = { field: 'title', order: 'asc' },
    initialFilterOptions = {},
    initialPagination = { page: 1, limit: 20 },
    useService = true,
    searchQuery: initialSearchQuery = '',
    autoLoad = true,
    persistFilters = false,
    persistSort = false,
    syncUrlParams = false,
    storageKeyPrefix = 'trackList',
  } = options;

  const [searchParams, setSearchParams] = useSearchParams();

  // Clés localStorage
  const filtersStorageKey = `${storageKeyPrefix}_filters`;
  const sortStorageKey = `${storageKeyPrefix}_sort`;

  // Fonction pour charger depuis localStorage
  const loadFromLocalStorage = useCallback(<T,>(key: string, defaultValue: T): T => {
    if (typeof window === 'undefined') {
      return defaultValue;
    }
    try {
      const stored = localStorage.getItem(key);
      if (stored) {
        return JSON.parse(stored) as T;
      }
    } catch (error) {
      console.error(`Error loading ${key} from localStorage:`, error);
    }
    return defaultValue;
  }, []);

  // Fonction pour charger depuis URL params
  const loadFromUrlParams = useCallback(() => {
    const urlFilters: TrackFilterOptions = {};
    const urlSort: TrackSortOptions = { field: 'title', order: 'asc' };
    const urlSearchQuery = searchParams.get('search') || '';

    // Charger les filtres depuis URL
    const genre = searchParams.get('genre');
    const artist = searchParams.get('artist');
    const album = searchParams.get('album');
    const year = searchParams.get('year');
    const minDuration = searchParams.get('minDuration');
    const maxDuration = searchParams.get('maxDuration');

    if (genre) urlFilters.genre = genre;
    if (artist) urlFilters.artist = artist;
    if (album) urlFilters.album = album;
    if (year) urlFilters.year = Number(year);
    if (minDuration) urlFilters.minDuration = Number(minDuration);
    if (maxDuration) urlFilters.maxDuration = Number(maxDuration);

    // Charger le tri depuis URL
    const sortField = searchParams.get('sortField');
    const sortOrder = searchParams.get('sortOrder');
    if (sortField && ['title', 'artist', 'album', 'duration', 'date', 'popularity'].includes(sortField)) {
      urlSort.field = sortField as TrackSortOption;
    }
    if (sortOrder && ['asc', 'desc'].includes(sortOrder)) {
      urlSort.order = sortOrder as SortOrder;
    }

    return { urlFilters, urlSort, urlSearchQuery };
  }, [searchParams]);

  // Initialiser les états avec priorité : URL params > localStorage > initial values
  const getInitialState = useCallback(() => {
    let filters = initialFilterOptions;
    let sort = initialSortOptions;
    let search = initialSearchQuery;

    if (syncUrlParams) {
      const { urlFilters, urlSort, urlSearchQuery } = loadFromUrlParams();
      if (Object.keys(urlFilters).length > 0) filters = urlFilters;
      if (urlSort.field !== 'title' || urlSort.order !== 'asc') sort = urlSort;
      if (urlSearchQuery) search = urlSearchQuery;
    } else {
      if (persistFilters) {
        const storedFilters = loadFromLocalStorage<TrackFilterOptions>(filtersStorageKey, {});
        if (Object.keys(storedFilters).length > 0) filters = storedFilters;
      }
      if (persistSort) {
        const storedSort = loadFromLocalStorage<TrackSortOptions>(sortStorageKey, { field: 'title', order: 'asc' });
        if (storedSort.field && storedSort.order) sort = storedSort;
      }
    }

    return { filters, sort, search };
  }, [initialFilterOptions, initialSortOptions, initialSearchQuery, syncUrlParams, persistFilters, persistSort, filtersStorageKey, sortStorageKey, loadFromLocalStorage, loadFromUrlParams]);

  const initialState = getInitialState();

  const [tracks, setTracks] = useState<Track[]>(initialTracks);
  const [displayMode, setDisplayMode] = useState<TrackListDisplayMode>(initialDisplayMode);
  const [sortOptions, setSortOptions] = useState<TrackSortOptions>(initialState.sort);
  const [filterOptions, setFilterOptions] = useState<TrackFilterOptions>(initialState.filters);
  const [pagination, setPagination] = useState<PaginationOptions>(initialPagination);
  const [searchQuery, setSearchQuery] = useState<string>(initialState.search);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  const [total, setTotal] = useState(0);
  const [totalPages, setTotalPages] = useState(0);

  // Charger les tracks depuis le service
  const loadTracks = useCallback(async () => {
    if (!useService) {
      return;
    }

    setIsLoading(true);
    setError(null);

    try {
      const response: PaginatedResponse<Track> = await getTracks({
        pagination,
        filters: filterOptions,
        sort: sortOptions,
        search: searchQuery || undefined,
      });

      setTracks(response.data);
      setTotal(response.total);
      setTotalPages(response.totalPages);
      setPagination({ page: response.page, limit: response.limit });
    } catch (err) {
      const error = err instanceof Error ? err : new Error('Erreur lors du chargement des pistes');
      setError(error);
      setTracks([]);
      setTotal(0);
      setTotalPages(0);
    } finally {
      setIsLoading(false);
    }
  }, [useService, pagination, filterOptions, sortOptions, searchQuery]);

  // Recharger les tracks (rafraîchir)
  const refreshTracks = useCallback(async () => {
    await loadTracks();
  }, [loadTracks]);

  // Polling automatique si des tracks sont en cours de traitement
  useEffect(() => {
    if (!useService) return;

    const hasProcessingTracks = tracks.some(
      (track: any) => track.status === 'processing' || track.status === 'uploading' || track.stream_status === 'processing'
    );

    if (hasProcessingTracks) {
      const interval = setInterval(() => {
        loadTracks();
      }, 5000); // Poll every 5 seconds

      return () => clearInterval(interval);
    }
  }, [tracks, useService, loadTracks]);

  // Charger automatiquement au montage et quand les options changent (si useService est true)
  useEffect(() => {
    if (useService && autoLoad) {
      loadTracks();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [pagination.page, pagination.limit, filterOptions, sortOptions.field, sortOptions.order, searchQuery, useService, autoLoad]);

  // Filtrer et trier côté client si useService est false
  const filteredTracksResult = useMemo(() => {
    if (useService) {
      return tracks; // Les tracks sont déjà filtrés/triés par le serveur
    }

    let filtered = [...tracks];

    // Filtrer par genre
    if (filterOptions.genre) {
      filtered = filtered.filter((track) => track.genre === filterOptions.genre);
    }

    // Filtrer par artiste
    if (filterOptions.artist) {
      filtered = filtered.filter((track) => track.artist === filterOptions.artist);
    }

    // Filtrer par album
    if (filterOptions.album) {
      filtered = filtered.filter((track) => track.album === filterOptions.album);
    }

    // Filtrer par durée minimale
    if (filterOptions.minDuration) {
      filtered = filtered.filter((track) => track.duration >= filterOptions.minDuration!);
    }

    // Filtrer par durée maximale
    if (filterOptions.maxDuration) {
      filtered = filtered.filter((track) => track.duration <= filterOptions.maxDuration!);
    }

    // Recherche côté client
    if (searchQuery) {
      const query = searchQuery.toLowerCase();
      filtered = filtered.filter(
        (track) =>
          track.title.toLowerCase().includes(query) ||
          track.artist?.toLowerCase().includes(query) ||
          track.album?.toLowerCase().includes(query)
      );
    }

    // Trier
    filtered.sort((a, b) => {
      let aValue: string | number = '';
      let bValue: string | number = '';

      switch (sortOptions.field) {
        case 'title':
          aValue = a.title.toLowerCase();
          bValue = b.title.toLowerCase();
          break;
        case 'artist':
          aValue = (a.artist || '').toLowerCase();
          bValue = (b.artist || '').toLowerCase();
          break;
        case 'album':
          aValue = (a.album || '').toLowerCase();
          bValue = (b.album || '').toLowerCase();
          break;
        case 'duration':
          aValue = a.duration;
          bValue = b.duration;
          break;
        case 'date':
        case 'popularity':
          return 0;
      }

      if (aValue < bValue) {
        return sortOptions.order === 'asc' ? -1 : 1;
      }
      if (aValue > bValue) {
        return sortOptions.order === 'asc' ? 1 : -1;
      }
      return 0;
    });

    // Pagination côté client
    const start = (pagination.page - 1) * pagination.limit;
    const end = start + pagination.limit;
    const paginated = filtered.slice(start, end);

    // Mettre à jour le total (via useEffect pour éviter les re-renders)
    if (!useService) {
      // Utiliser un effet pour mettre à jour le total sans causer de re-render
      setTimeout(() => {
        setTotal(filtered.length);
        setTotalPages(Math.ceil(filtered.length / pagination.limit));
      }, 0);
    }

    return paginated;
  }, [tracks, filterOptions, sortOptions, searchQuery, pagination, useService]);

  // Persister les filtres dans localStorage
  useEffect(() => {
    if (persistFilters && typeof window !== 'undefined') {
      try {
        localStorage.setItem(filtersStorageKey, JSON.stringify(filterOptions));
      } catch (error) {
        console.error('Error persisting filters to localStorage:', error);
      }
    }
  }, [filterOptions, persistFilters, filtersStorageKey]);

  // Persister le tri dans localStorage
  useEffect(() => {
    if (persistSort && typeof window !== 'undefined') {
      try {
        localStorage.setItem(sortStorageKey, JSON.stringify(sortOptions));
      } catch (error) {
        console.error('Error persisting sort to localStorage:', error);
      }
    }
  }, [sortOptions, persistSort, sortStorageKey]);

  // Synchroniser avec les URL params
  useEffect(() => {
    if (syncUrlParams) {
      const params = new URLSearchParams(searchParams);

      // Mettre à jour les filtres dans l'URL
      if (filterOptions.genre) {
        params.set('genre', filterOptions.genre);
      } else {
        params.delete('genre');
      }
      if (filterOptions.artist) {
        params.set('artist', filterOptions.artist);
      } else {
        params.delete('artist');
      }
      if (filterOptions.album) {
        params.set('album', filterOptions.album);
      } else {
        params.delete('album');
      }
      if (filterOptions.year) {
        params.set('year', String(filterOptions.year));
      } else {
        params.delete('year');
      }
      if (filterOptions.minDuration) {
        params.set('minDuration', String(filterOptions.minDuration));
      } else {
        params.delete('minDuration');
      }
      if (filterOptions.maxDuration) {
        params.set('maxDuration', String(filterOptions.maxDuration));
      } else {
        params.delete('maxDuration');
      }

      // Mettre à jour le tri dans l'URL
      params.set('sortField', sortOptions.field);
      params.set('sortOrder', sortOptions.order);

      // Mettre à jour la recherche dans l'URL
      if (searchQuery) {
        params.set('search', searchQuery);
      } else {
        params.delete('search');
      }

      setSearchParams(params, { replace: true });
    }
  }, [filterOptions, sortOptions, searchQuery, syncUrlParams, searchParams, setSearchParams]);

  const setSortField = useCallback(
    (field: TrackSortOption) => {
      setSortOptions((prev) => ({ ...prev, field }));
      // Si on utilise le service, on recharge automatiquement
      if (useService && autoLoad) {
        setPagination((prev) => ({ ...prev, page: 1 })); // Reset à la page 1
      }
    },
    [useService, autoLoad]
  );

  const setSortOrder = useCallback(
    (order: SortOrder) => {
      setSortOptions((prev) => ({ ...prev, order }));
      if (useService && autoLoad) {
        setPagination((prev) => ({ ...prev, page: 1 }));
      }
    },
    [useService, autoLoad]
  );

  const handleSetFilterOptions = useCallback(
    (options: TrackFilterOptions) => {
      setFilterOptions(options);
      if (useService && autoLoad) {
        setPagination((prev) => ({ ...prev, page: 1 })); // Reset à la page 1
      }
    },
    [useService, autoLoad]
  );

  const clearFilters = useCallback(() => {
    setFilterOptions({});
    setSearchQuery('');
    if (useService && autoLoad) {
      setPagination((prev) => ({ ...prev, page: 1 }));
    }
  }, [useService, autoLoad]);

  const handleSetPagination = useCallback(
    (newPagination: PaginationOptions) => {
      setPagination(newPagination);
    },
    []
  );

  const setPage = useCallback(
    (page: number) => {
      setPagination((prev) => ({ ...prev, page }));
    },
    []
  );

  const setLimit = useCallback(
    (limit: number) => {
      setPagination((prev) => ({ ...prev, limit, page: 1 })); // Reset à la page 1
    },
    []
  );

  const handleSetSearchQuery = useCallback(
    (query: string) => {
      setSearchQuery(query);
      if (useService && autoLoad) {
        setPagination((prev) => ({ ...prev, page: 1 }));
      }
    },
    [useService, autoLoad]
  );

  const addTrack = useCallback((track: Track) => {
    setTracks((prev) => [...prev, track]);
    if (!useService) {
      setTotal((prev) => prev + 1);
    }
  }, [useService]);

  const removeTrack = useCallback(
    (trackId: number) => {
      setTracks((prev) => prev.filter((track) => track.id !== trackId));
      if (!useService) {
        setTotal((prev) => Math.max(0, prev - 1));
      }
    },
    [useService]
  );

  const updateTrack = useCallback((updatedTrack: Track) => {
    setTracks((prev) =>
      prev.map((track) => (track.id === updatedTrack.id ? updatedTrack : track))
    );
  }, []);

  // Mettre à jour le total pour le mode client
  useEffect(() => {
    if (!useService) {
      let filtered = [...tracks];
      
      if (filterOptions.genre) {
        filtered = filtered.filter((track) => track.genre === filterOptions.genre);
      }
      if (filterOptions.artist) {
        filtered = filtered.filter((track) => track.artist === filterOptions.artist);
      }
      if (filterOptions.album) {
        filtered = filtered.filter((track) => track.album === filterOptions.album);
      }
      if (filterOptions.minDuration) {
        filtered = filtered.filter((track) => track.duration >= filterOptions.minDuration!);
      }
      if (filterOptions.maxDuration) {
        filtered = filtered.filter((track) => track.duration <= filterOptions.maxDuration!);
      }
      if (searchQuery) {
        const query = searchQuery.toLowerCase();
        filtered = filtered.filter(
          (track) =>
            track.title.toLowerCase().includes(query) ||
            track.artist?.toLowerCase().includes(query) ||
            track.album?.toLowerCase().includes(query)
        );
      }

      setTotal(filtered.length);
      setTotalPages(Math.ceil(filtered.length / pagination.limit));
    }
  }, [tracks, filterOptions, searchQuery, pagination, useService]);

  return {
    tracks: filteredTracksResult,
    filteredTracks: filteredTracksResult,
    displayMode,
    sortOptions,
    filterOptions,
    isLoading,
    error,
    pagination,
    total,
    totalPages,
    setTracks,
    setDisplayMode,
    setSortField,
    setSortOrder,
    setFilterOptions: handleSetFilterOptions,
    clearFilters,
    setPagination: handleSetPagination,
    setPage,
    setLimit,
    setSearchQuery: handleSetSearchQuery,
    addTrack,
    removeTrack,
    updateTrack,
    loadTracks,
    refreshTracks,
  };
}
