import { useCallback, useEffect, useMemo, useState } from 'react';

import { Track, TrackResource } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext';
import { SessionServiceProps } from '@/service/session';
import { DataStoreType, useDataStore } from '@/utils/data-store';
import { DataTools, TypeCheck } from '@/utils/data-tools';
import { isArrayOf, isNumber } from '@/utils/validator';

export type TrackServiceProps = {
  store: DataStoreType<Track>;
};

export const useTrackService = (): TrackServiceProps => {
  const { track } = useServiceContext();
  return track;
};

export const useTrackServiceWrapped = (
  session: SessionServiceProps
): TrackServiceProps => {
  const store = useDataStore<Track>(
    {
      restApiName: 'TRACK',
      primaryKey: 'id',
      available: session.token !== undefined,
      getsCall: () => {
        return TrackResource.gets({
          restConfig: session.getRestConfig(),
        });
      },
    },
    [session.token]
  );

  return { store };
};

export const useSpecificTrack = (id: number | undefined) => {
  const { store } = useTrackService();
  const dataTrack = useMemo(() => {
    return store.get(id);
  }, [store.data, id]);
  return { isLoading: store.isLoading, dataTrack };
};
/**
 * Get all the track for a specific artist
 * @param idArtist - Id of the artist.
 * @returns a promise on the list of track elements
 */
export const useTracksOfAnArtist = (idArtist?: number) => {
  const { store } = useTrackService();
  const tracksOnAnArtist = useMemo(() => {
    if (idArtist) {
      return DataTools.getsWhere(
        store.data,
        [
          {
            check: TypeCheck.CONTAINS,
            key: 'artists',
            value: idArtist,
          },
        ],
        ['track', 'name']
      );
    }
    return [];
  }, [store.data, idArtist]);
  return { isLoading: store.isLoading, tracksOnAnArtist };
};

/**
 * Get the number of track in this artist ID
 * @param id - Id of the artist.
 * @returns The number of track present in this artist
 */
export const useCountTracksOfAnArtist = (idArtist?: number) => {
  const { isLoading, tracksOnAnAlbum } = useTracksOfAnAlbum(idArtist);
  const countTracksOnAnArtist = useMemo(
    () => tracksOnAnAlbum?.length ?? 0,
    [tracksOnAnAlbum]
  );
  return { isLoading, countTracksOnAnArtist };
};

/**
 * Get all the track for a specific artist
 * @param idGender - Id of the artist.
 * @returns a promise on the list of track elements
 */
export const useTracksOfAGender = (idGender?: number) => {
  const { store } = useTrackService();
  const tracksOnAGender = useMemo(() => {
    if (idGender) {
      return DataTools.getsWhere(
        store.data,
        [
          {
            check: TypeCheck.CONTAINS,
            key: 'genderId',
            value: idGender,
          },
        ],
        ['name', 'track']
      );
    }
    return [];
  }, [store.data, idGender]);
  return { isLoading: store.isLoading, tracksOnAGender };
};

/**
 * Get the number of track in this artist ID
 * @param id - Id of the gender.
 * @returns The number of track present in this artist
 */
export const useCountTracksOfAGender = (idGender?: number) => {
  const { isLoading, tracksOnAGender } = useTracksOfAGender(idGender);
  const countTracksOnAGender = useMemo(
    () => tracksOnAGender?.length ?? 0,
    [tracksOnAGender]
  );
  return { isLoading, countTracksOnAGender };
};

/**
 * Get all the album of a specific artist
 * @param artistId - ID of the artist
 * @returns the required List.
 */
export const useAlbumIdsOfAnArtist = (idArtist?: number) => {
  const { isLoading, tracksOnAnArtist } = useTracksOfAnArtist(idArtist);
  const albumIdsOfAnArtist = useMemo(() => {
    // extract a single time all value "id" in an array
    const listAlbumId = DataTools.extractLimitOne(tracksOnAnArtist, 'albumId');
    if (isArrayOf(listAlbumId, isNumber)) {
      return listAlbumId;
    } else {
      console.log(
        'Fail to parse the result of the list value (impossible case)'
      );
      return [];
    }
  }, [tracksOnAnArtist]);
  return { isLoading, albumIdsOfAnArtist };
};

export const useTracksOfAnAlbum = (idAlbum?: number) => {
  const { store } = useTrackService();
  const tracksOnAnAlbum = useMemo(() => {
    if (idAlbum) {
      return DataTools.getsWhere(
        store.data,
        [
          {
            check: TypeCheck.EQUAL,
            key: 'albumId',
            value: idAlbum,
          },
        ],
        ['track', 'name', 'id']
      );
    }
  }, [store.data, idAlbum]);
  return { isLoading: store.isLoading, tracksOnAnAlbum };
};

/**
 * Get the number of track in this season ID
 * @param AlbumId - Id of the album.
 * @returns The number of element present in this season
 */
export const useCountTracksWithAlbumId = (albumId?: number) => {
  const { isLoading, tracksOnAnAlbum } = useTracksOfAnAlbum(albumId);
  const countTracksOfAnAlbum = useMemo(
    () => tracksOnAnAlbum?.length ?? 0,
    [tracksOnAnAlbum]
  );
  return { isLoading, countTracksOfAnAlbum };
};

/**
 * Get all the track for a specific artist
 * @param idArtist - Id of the artist.
 * @returns a promise on the list of track elements
 */
export const useTracksOfArtistWithNoAlbum = (idArtist: number) => {
  const { store } = useTrackService();
  const tracksOnAnArtistWithNoAlbum = useMemo(() => {
    if (idArtist) {
      return DataTools.getsWhere(
        store.data,
        [
          {
            check: TypeCheck.CONTAINS,
            key: 'artists',
            value: idArtist,
          },
          {
            check: TypeCheck.EQUAL,
            key: 'albumId',
            value: undefined,
          },
        ],
        ['track', 'name']
      );
    }
    return [];
  }, [store.data, idArtist]);
  return { isLoading: store.isLoading, tracksOnAnArtistWithNoAlbum };
};

/**
 * Get all the track for a specific artist
 * @param startName - basic starting name.
 * @returns a promise on the list of track elements
 */
export const useTracksWithStartName = (
  startName: string | string[],
  invert: boolean
) => {
  const { store } = useTrackService();
  const tracksStartsWith = useMemo(() => {
    return DataTools.getsWhere(
      store.data,
      [
        {
          check: invert ? TypeCheck.STARTS_NOT_WITH : TypeCheck.STARTS_WITH,
          key: 'name',
          value: startName,
        },
      ],
      ['name', 'track']
    );
  }, [store.data, startName, invert]);
  return { isLoading: store.isLoading, tracksStartsWith };
};
