import type { AxiosRequestConfig } from 'axios';
import type { Api } from '@jellyfin/sdk';
import type {
    ArtistsApiGetArtistsRequest,
    BaseItemDto,
    ItemsApiGetItemsRequest,
    PersonsApiGetPersonsRequest
} from '@jellyfin/sdk/lib/generated-client';
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import { ItemFields } from '@jellyfin/sdk/lib/generated-client/models/item-fields';
import { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type';
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
import { getPersonsApi } from '@jellyfin/sdk/lib/utils/api/persons-api';
import { getArtistsApi } from '@jellyfin/sdk/lib/utils/api/artists-api';
import { useQuery } from '@tanstack/react-query';
import { useApi } from '../useApi';
import type { CardOptions } from 'types/cardOptions';
import { CardShape } from 'utils/card';

const QUERY_OPTIONS = {
    limit: 100,
    fields: [
        ItemFields.PrimaryImageAspectRatio,
        ItemFields.CanDelete,
        ItemFields.MediaSourceCount
    ],
    enableTotalRecordCount: false,
    imageTypeLimit: 1
};

const fetchItemsByType = async (
    api: Api,
    userId?: string,
    params?: ItemsApiGetItemsRequest,
    options?: AxiosRequestConfig
) => {
    const response = await getItemsApi(api).getItems(
        {
            ...QUERY_OPTIONS,
            userId: userId,
            recursive: true,
            ...params
        },
        options
    );
    return response.data;
};

const fetchPeople = async (
    api: Api,
    userId: string,
    params?: PersonsApiGetPersonsRequest,
    options?: AxiosRequestConfig
) => {
    const response = await getPersonsApi(api).getPersons(
        {
            ...QUERY_OPTIONS,
            userId: userId,
            ...params
        },
        options
    );
    return response.data;
};

const fetchArtists = async (
    api: Api,
    userId: string,
    params?: ArtistsApiGetArtistsRequest,
    options?: AxiosRequestConfig
) => {
    const response = await getArtistsApi(api).getArtists(
        {
            ...QUERY_OPTIONS,
            userId: userId,
            ...params
        },
        options
    );
    return response.data;
};

const isMovies = (collectionType: string) =>
    collectionType === CollectionType.Movies;

const isMusic = (collectionType: string) =>
    collectionType === CollectionType.Music;

const isTVShows = (collectionType: string) =>
    collectionType === CollectionType.Tvshows;

const isLivetv = (collectionType: string) =>
    collectionType === CollectionType.Livetv;

const LIVETV_CARD_OPTIONS = {
    preferThumb: true,
    inheritThumb: false,
    showParentTitleOrTitle: true,
    showTitle: false,
    coverImage: true,
    overlayMoreButton: true,
    showAirTime: true,
    showAirDateTime: true,
    showChannelName: true
};

export interface Section {
    title: string
    items: BaseItemDto[];
    cardOptions?: CardOptions;
}

export const useSearchItems = (
    parentId?: string,
    collectionType?: string,
    searchTerm?: string
) => {
    const { api, user } = useApi();
    const userId = user?.Id;

    return useQuery({
        queryKey: ['SearchItems', { parentId, collectionType, searchTerm }],
        queryFn: async ({ signal }) => {
            if (!api) throw new Error('No API instance available');
            if (!userId) throw new Error('No User ID provided');

            const sections: Section[] = [];

            const addSection = (
                title: string,
                items: BaseItemDto[] | null | undefined,
                cardOptions?: CardOptions
            ) => {
                if (items && items?.length > 0) {
                    sections.push({ title, items, cardOptions });
                }
            };

            // Livetv libraries
            if (collectionType && isLivetv(collectionType)) {
                // Movies row
                const moviesData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.LiveTvProgram],
                        isMovie: true,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Movies', moviesData.Items, {
                    ...LIVETV_CARD_OPTIONS,
                    shape: CardShape.PortraitOverflow
                });

                // Episodes row
                const episodesData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.LiveTvProgram],
                        isMovie: false,
                        isSeries: true,
                        isSports: false,
                        isKids: false,
                        isNews: false,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Episodes', episodesData.Items, {
                    ...LIVETV_CARD_OPTIONS
                });

                // Sports row
                const sportsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.LiveTvProgram],
                        isSports: true,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Sports', sportsData.Items, {
                    ...LIVETV_CARD_OPTIONS
                });

                // Kids row
                const kidsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.LiveTvProgram],
                        isKids: true,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Kids', kidsData.Items, {
                    ...LIVETV_CARD_OPTIONS
                });

                // News row
                const newsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.LiveTvProgram],
                        isNews: true,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('News', newsData.Items, {
                    ...LIVETV_CARD_OPTIONS
                });

                // Programs row
                const programsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.LiveTvProgram],
                        isMovie: false,
                        isSeries: false,
                        isSports: false,
                        isKids: false,
                        isNews: false,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Programs', programsData.Items, {
                    ...LIVETV_CARD_OPTIONS
                });

                // Channels row
                const channelsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.TvChannel],
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Channels', channelsData.Items);
            }

            // Movie libraries
            if (!collectionType || isMovies(collectionType)) {
                // Movies row
                const moviesData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.Movie],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Movies', moviesData.Items, {
                    showYear: true
                });
            }

            // TV Show libraries
            if (!collectionType || isTVShows(collectionType)) {
                // Shows row
                const showsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.Series],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Shows', showsData.Items, {
                    showYear: true
                });

                // Episodes row
                const episodesData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.Episode],
                        parentId: parentId,
                        isMissing: user?.Configuration?.DisplayMissingEpisodes,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Episodes', episodesData.Items, {
                    coverImage: true,
                    showParentTitle: true
                });
            }

            // People are included for Movies and TV Shows
            if (
                !collectionType
                || isMovies(collectionType)
                || isTVShows(collectionType)
            ) {
                // People row
                const peopleData = await fetchPeople(
                    api,
                    userId,
                    {
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('People', peopleData.Items, {
                    coverImage: true
                });
            }

            // Music libraries
            if (!collectionType || isMusic(collectionType)) {
                // Playlists row
                const playlistsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.Playlist],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Playlists', playlistsData.Items);

                // Artists row
                const artistsData = await fetchArtists(
                    api,
                    userId,
                    {
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Artists', artistsData.Items, {
                    coverImage: true
                });

                // Albums row
                const albumsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.MusicAlbum],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Albums', albumsData.Items, {
                    showYear: true
                });

                // Songs row
                const songsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.Audio],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Songs', songsData.Items, {
                    showParentTitle: true,
                    shape: CardShape.SquareOverflow
                });
            }

            // Other libraries do not support in-library search currently
            if (!collectionType) {
                // Videos row
                const videosData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        mediaTypes: [MediaType.Video],
                        excludeItemTypes: [
                            BaseItemKind.Movie,
                            BaseItemKind.Episode,
                            BaseItemKind.TvChannel
                        ],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );

                addSection('HeaderVideos', videosData.Items, {
                    showParentTitle: true
                });

                // Programs row
                const programsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.LiveTvProgram],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Programs', programsData.Items, {
                    ...LIVETV_CARD_OPTIONS
                });

                // Channels row
                const channelsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.TvChannel],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Channels', channelsData.Items);

                // Photo Albums row
                const photoAlbumsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.PhotoAlbum],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('HeaderPhotoAlbums', photoAlbumsData.Items);

                // Photos row
                const photosData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.Photo],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Photos', photosData.Items);

                // Audio Books row
                const audioBooksData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.AudioBook],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('HeaderAudioBooks', audioBooksData.Items);

                // Books row
                const booksData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.Book],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Books', booksData.Items);

                // Collections row
                const collectionsData = await fetchItemsByType(
                    api,
                    userId,
                    {
                        includeItemTypes: [BaseItemKind.BoxSet],
                        parentId: parentId,
                        searchTerm: searchTerm
                    },
                    { signal }
                );
                addSection('Collections', collectionsData.Items);
            }

            return sections;
        },
        enabled: !!api && !!userId
    });
};
