import type {
    ItemListStateActions,
    ItemListStateItemWithRequiredProperties,
} from '/@/renderer/components/item-list/helpers/item-list-state';

import { useSuspenseQuery } from '@tanstack/react-query';
import { ReactNode, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { generatePath, useParams } from 'react-router';

import styles from './album-detail-content.module.css';

import { useGridCarouselContainerQuery } from '/@/renderer/components/grid-carousel/grid-carousel-v2';
import { useItemListStateSubscription } from '/@/renderer/components/item-list/helpers/item-list-state';
import { useItemListColumnReorder } from '/@/renderer/components/item-list/helpers/use-item-list-column-reorder';
import { useItemListColumnResize } from '/@/renderer/components/item-list/helpers/use-item-list-column-resize';
import { SONG_TABLE_COLUMNS } from '/@/renderer/components/item-list/item-table-list/default-columns';
import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
import { ItemControls } from '/@/renderer/components/item-list/types';
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import { AlbumInfiniteCarousel } from '/@/renderer/features/albums/components/album-infinite-carousel';
import { usePlayer } from '/@/renderer/features/player/context/player-context';
import {
    ListConfigMenu,
    SONG_DISPLAY_TYPES,
} from '/@/renderer/features/shared/components/list-config-menu';
import {
    CLIENT_SIDE_SONG_FILTERS,
    ListSortByDropdownControlled,
} from '/@/renderer/features/shared/components/list-sort-by-dropdown';
import { ListSortOrderToggleButtonControlled } from '/@/renderer/features/shared/components/list-sort-order-toggle-button';
import { FILTER_KEYS, searchLibraryItems } from '/@/renderer/features/shared/utils';
import { useHotkeys } from '/@/renderer/hooks/use-hotkeys';
import { AppRoute } from '/@/renderer/router/routes';
import { useCurrentServer, usePlayerSong } from '/@/renderer/store';
import { useExternalLinks, useSettingsStore } from '/@/renderer/store/settings.store';
import { sentenceCase, titleCase } from '/@/renderer/utils';
import { replaceURLWithHTMLLinks } from '/@/renderer/utils/linkify';
import { normalizeReleaseTypes } from '/@/renderer/utils/normalize-release-types';
import { setJsonSearchParam } from '/@/renderer/utils/query-params';
import { sortSongList } from '/@/shared/api/utils';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
import { Group } from '/@/shared/components/group/group';
import { Icon } from '/@/shared/components/icon/icon';
import { Pill, PillLink } from '/@/shared/components/pill/pill';
import { Spoiler } from '/@/shared/components/spoiler/spoiler';
import { Stack } from '/@/shared/components/stack/stack';
import { TextInput } from '/@/shared/components/text-input/text-input';
import { Text } from '/@/shared/components/text/text';
import { useDebouncedValue } from '/@/shared/hooks/use-debounced-value';
import {
    Album,
    AlbumListSort,
    ExplicitStatus,
    LibraryItem,
    ServerType,
    Song,
    SongListSort,
    SortOrder,
} from '/@/shared/types/domain-types';
import { ItemListKey, ListDisplayType, Play } from '/@/shared/types/types';

const MetadataPillGroup = ({
    items,
    title,
}: {
    items: undefined | { id: string; value: ReactNode | string | undefined }[];
    title: string;
}) => {
    if (!items || items.length === 0) return null;

    return (
        <Stack align="center" className={styles.metadataPillGroup} gap="xs">
            <Text fw={600} isNoSelect size="sm" tt="uppercase">
                {title}
            </Text>
            <div className={styles['pill-group-wrapper']}>
                <Pill.Group>
                    {items.map((tag, index) => (
                        <Pill key={`item-${tag.id}-${index}`} size="md">
                            {tag.value}
                        </Pill>
                    ))}
                </Pill.Group>
            </div>
        </Stack>
    );
};

interface AlbumMetadataTagsProps {
    album: Album | undefined;
}

const MOOD_TAG = 'mood';
const GROUPING_TAG = 'grouping';
const RELEASE_COUNTRY_TAG = 'releasecountry';
const RELEASE_STATUS_TAG = 'releasestatus';

const AlbumMetadataTags = ({ album }: AlbumMetadataTagsProps) => {
    const { t } = useTranslation();

    const defaultTagItems = useMemo(() => {
        if (!album) return [];

        const releaseTypes = normalizeReleaseTypes(album.releaseTypes ?? [], t).map((type) => ({
            id: type,
            value: titleCase(type),
        }));

        const releaseCountries =
            album.tags?.[RELEASE_COUNTRY_TAG]?.map((country) => ({
                id: country,
                value: country,
            })) || [];

        const releaseStatuses =
            album.tags?.[RELEASE_STATUS_TAG]?.map((status) => ({
                id: status,
                value: status,
            })) || [];

        const items: Array<{ id: string; value: ReactNode | string | undefined }> = [];

        items.push(
            ...releaseTypes,
            {
                id: 'isCompilation',
                value: album?.isCompilation ? t('filter.isCompilation') : undefined,
            },
            ...releaseCountries,
            ...releaseStatuses,
            {
                id: 'explicitStatus',
                value:
                    album.explicitStatus === ExplicitStatus.EXPLICIT
                        ? t('common.explicit')
                        : album.explicitStatus === ExplicitStatus.CLEAN
                          ? t('common.clean')
                          : undefined,
            },
        );

        return items.filter((item) => item.value);
    }, [album, t]);

    const moodTagItems = useMemo(() => {
        if (!album) return [];

        return album.tags?.[MOOD_TAG]?.map((tag) => ({
            id: tag,
            value: tag,
        }));
    }, [album]);

    const groupingItems = useMemo(() => {
        if (!album) return [];

        return (
            album.tags?.[GROUPING_TAG]?.map((tag) => {
                if (album._serverType !== ServerType.NAVIDROME) {
                    return { id: tag, label: tag, url: null };
                }

                const searchParams = new URLSearchParams();
                const paramsWithCustom = setJsonSearchParam(
                    searchParams,
                    FILTER_KEYS.ALBUM._CUSTOM,
                    { grouping: [tag] },
                );
                return {
                    id: tag,
                    label: tag,
                    url: `${AppRoute.LIBRARY_ALBUMS}?${paramsWithCustom.toString()}`,
                };
            }) ?? []
        );
    }, [album]);

    const recordLabels = useMemo(() => {
        if (!album?.recordLabels || album.recordLabels.length === 0) return [];

        return album.recordLabels.map((label) => {
            if (album._serverType === ServerType.SUBSONIC) {
                return { id: label, label: label, url: null };
            }

            const searchParams = new URLSearchParams();
            const customFilters =
                album._serverType === ServerType.JELLYFIN
                    ? { Studios: [label] }
                    : { recordlabel: [label] };
            const paramsWithCustom = setJsonSearchParam(
                searchParams,
                FILTER_KEYS.ALBUM._CUSTOM,
                customFilters,
            );
            const url = `${AppRoute.LIBRARY_ALBUMS}?${paramsWithCustom.toString()}`;

            return {
                id: label,
                label,
                url,
            };
        });
    }, [album]);

    return (
        <>
            <MetadataPillGroup items={defaultTagItems} title={t('common.tags')} />

            {recordLabels.length > 0 && (
                <Stack align="center" className={styles.metadataPillGroup} gap="xs">
                    <Text fw={600} isNoSelect size="sm" tt="uppercase">
                        {t('common.recordLabel')}
                    </Text>
                    <div className={styles['pill-group-wrapper']}>
                        <Pill.Group>
                            {recordLabels.map((recordLabel) =>
                                recordLabel.url ? (
                                    <PillLink
                                        key={`recordlabel-${recordLabel.id}`}
                                        size="md"
                                        to={recordLabel.url}
                                    >
                                        {recordLabel.label}
                                    </PillLink>
                                ) : (
                                    <Pill key={`recordlabel-${recordLabel.id}`} size="md">
                                        {recordLabel.label}
                                    </Pill>
                                ),
                            )}
                        </Pill.Group>
                    </div>
                </Stack>
            )}

            <MetadataPillGroup items={moodTagItems} title={t('common.mood')} />

            {groupingItems.length > 0 && (
                <Stack align="center" className={styles.metadataPillGroup} gap="xs">
                    <Text fw={600} isNoSelect size="sm" tt="uppercase">
                        {t('common.grouping')}
                    </Text>
                    <div className={styles['pill-group-wrapper']}>
                        <Pill.Group>
                            {groupingItems.map((item) =>
                                item.url ? (
                                    <PillLink key={`grouping-${item.id}`} size="md" to={item.url}>
                                        {item.label}
                                    </PillLink>
                                ) : (
                                    <Pill key={`grouping-${item.id}`} size="md">
                                        {item.label}
                                    </Pill>
                                ),
                            )}
                        </Pill.Group>
                    </div>
                </Stack>
            )}
        </>
    );
};

interface AlbumMetadataGenresProps {
    genres?: Array<{ id: string; name: string }>;
}

const AlbumMetadataGenres = ({ genres }: AlbumMetadataGenresProps) => {
    const { t } = useTranslation();

    if (!genres || genres.length === 0) return null;

    return (
        <Stack gap="xs">
            <Text fw={600} isNoSelect size="sm" tt="uppercase">
                {t('entity.genre', {
                    count: genres.length,
                })}
            </Text>
            <Pill.Group>
                {genres.map((genre) => (
                    <PillLink
                        key={`genre-${genre.id}`}
                        size="md"
                        to={generatePath(AppRoute.LIBRARY_GENRES_DETAIL, {
                            genreId: genre.id,
                        })}
                    >
                        {genre.name}
                    </PillLink>
                ))}
            </Pill.Group>
        </Stack>
    );
};

// interface AlbumMetadataArtistsProps {
//     artists?: Array<{ id: string; name: string }>;
// }

// const AlbumMetadataArtists = ({ artists }: AlbumMetadataArtistsProps) => {
//     const { t } = useTranslation();

//     if (!artists || artists.length === 0) return null;

//     return (
//         <Stack gap="xs">
//             <Text fw={600} isNoSelect size="sm" tt="uppercase">
//                 {t('entity.albumArtist', {
//                     count: artists.length,
//                 })}
//             </Text>
//             <Pill.Group>
//                 {artists.map((artist) => (
//                     <PillLink
//                         key={`artist-${artist.id}`}
//                         size="md"
//                         to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL, {
//                             albumArtistId: artist.id,
//                         })}
//                     >
//                         {artist.name}
//                     </PillLink>
//                 ))}
//             </Pill.Group>
//         </Stack>
//     );
// };

interface AlbumMetadataExternalLinksProps {
    albumArtist?: string;
    albumName?: string;
    externalLinks: boolean;
    lastFM: boolean;
    listenBrainz: boolean;
    mbzId?: null | string;
    mbzReleaseGroupId?: null | string;
    musicBrainz: boolean;
    nativeSpotify: boolean;
    qobuz: boolean;
    spotify: boolean;
}

const getListenBrainzUrl = (
    mbzReleaseGroupId: null | string,
    albumArtist?: string,
    albumName?: string,
) => {
    if (mbzReleaseGroupId) {
        return `https://listenbrainz.org/album/${mbzReleaseGroupId}`;
    }

    if (albumArtist || albumName) {
        return `https://listenbrainz.org/search/?search_term=${encodeURIComponent([albumArtist, albumName].filter(Boolean).join(' ').trim())}`;
    }

    return null;
};

const getQobuzUrl = (albumArtist?: string, albumName?: string) => {
    if (albumArtist || albumName) {
        return `https://www.qobuz.com/us-en/search/albums/${encodeURIComponent([albumArtist, albumName].filter(Boolean).join(' ').trim())}`;
    }

    return null;
};

const AlbumMetadataExternalLinks = ({
    albumArtist,
    albumName,
    externalLinks,
    lastFM,
    listenBrainz,
    mbzId,
    mbzReleaseGroupId,
    musicBrainz,
    nativeSpotify,
    qobuz,
    spotify,
}: AlbumMetadataExternalLinksProps) => {
    const { t } = useTranslation();

    const listenBrainzUrl = getListenBrainzUrl(mbzReleaseGroupId || null, albumArtist, albumName);
    const qobuzUrl = getQobuzUrl(albumArtist, albumName);

    if (!externalLinks || (!lastFM && !listenBrainz && !musicBrainz && !qobuz && !spotify)) {
        return null;
    }

    return (
        <Stack gap="xs">
            <Text fw={600} isNoSelect size="sm" tt="uppercase">
                {t('common.externalLinks')}
            </Text>
            <Group className={styles.externalLinksGroup} gap="xs">
                {lastFM && (
                    <ActionIcon
                        component="a"
                        href={`https://www.last.fm/music/${encodeURIComponent(
                            albumArtist || '',
                        )}/${encodeURIComponent(albumName || '')}`}
                        icon="brandLastfm"
                        iconProps={{
                            size: '2xl',
                        }}
                        radius="md"
                        rel="noopener noreferrer"
                        target="_blank"
                        tooltip={{
                            label: t('action.openIn.lastfm'),
                        }}
                        variant="subtle"
                    />
                )}
                {mbzId && musicBrainz ? (
                    <ActionIcon
                        component="a"
                        href={`https://musicbrainz.org/release/${mbzId}`}
                        icon="brandMusicBrainz"
                        iconProps={{
                            size: '2xl',
                        }}
                        radius="md"
                        rel="noopener noreferrer"
                        target="_blank"
                        tooltip={{
                            label: t('action.openIn.musicbrainz'),
                        }}
                        variant="subtle"
                    />
                ) : null}
                {listenBrainz && listenBrainzUrl && (
                    <ActionIcon
                        component="a"
                        href={listenBrainzUrl}
                        icon="brandListenBrainz"
                        iconProps={{
                            size: '2xl',
                        }}
                        radius="md"
                        rel="noopener noreferrer"
                        target="_blank"
                        tooltip={{
                            label: t('action.openIn.listenbrainz'),
                        }}
                        variant="subtle"
                    />
                )}
                {qobuz && qobuzUrl && (
                    <ActionIcon
                        component="a"
                        href={qobuzUrl}
                        icon="brandQobuz"
                        iconProps={{
                            size: '2xl',
                        }}
                        radius="md"
                        rel="noopener noreferrer"
                        target="_blank"
                        tooltip={{
                            label: t('action.openIn.qobuz'),
                        }}
                        variant="subtle"
                    />
                )}
                {spotify && (
                    <ActionIcon
                        component="a"
                        href={
                            nativeSpotify
                                ? `spotify:search:${encodeURIComponent(albumArtist || '')}%20${encodeURIComponent(albumName || '')}`
                                : `https://open.spotify.com/search/${encodeURIComponent(albumArtist || '')}%20${encodeURIComponent(albumName || '')}`
                        }
                        icon="brandSpotify"
                        iconProps={{
                            size: '2xl',
                        }}
                        radius="md"
                        rel="noopener noreferrer"
                        target={nativeSpotify ? undefined : '_blank'}
                        tooltip={{
                            label: t('action.openIn.spotify'),
                        }}
                        variant="subtle"
                    />
                )}
            </Group>
        </Stack>
    );
};

export const AlbumDetailContent = () => {
    const { albumId } = useParams() as { albumId: string };
    const server = useCurrentServer();
    const detailQuery = useSuspenseQuery(
        albumQueries.detail({ query: { id: albumId }, serverId: server.id }),
    );

    const { externalLinks, lastFM, listenBrainz, musicBrainz, nativeSpotify, qobuz, spotify } =
        useExternalLinks();

    const comment = detailQuery?.data?.comment;

    const releaseYear = detailQuery?.data?.releaseYear;
    const labels = detailQuery?.data?.recordLabels;

    const mbzId = detailQuery?.data?.mbzId;

    return (
        <div className={styles.contentContainer}>
            <div className={styles.detailContainer}>
                {comment && (
                    <Spoiler maxHeight={75}>
                        <Text pb="md">{replaceURLWithHTMLLinks(comment)}</Text>
                    </Spoiler>
                )}
                <div className={styles.contentLayout}>
                    <div className={styles.songsColumn}>
                        {detailQuery?.data?.songs && detailQuery.data.songs.length > 0 && (
                            <AlbumDetailSongsTable songs={detailQuery.data.songs} />
                        )}
                    </div>
                    <div className={styles.metadataColumn}>
                        <AlbumMetadataGenres genres={detailQuery?.data?.genres} />
                        <AlbumMetadataTags album={detailQuery?.data} />
                        <AlbumMetadataExternalLinks
                            albumArtist={detailQuery?.data?.albumArtistName}
                            albumName={detailQuery?.data?.name}
                            externalLinks={externalLinks}
                            lastFM={lastFM}
                            listenBrainz={listenBrainz}
                            mbzId={mbzId || undefined}
                            mbzReleaseGroupId={detailQuery?.data?.mbzReleaseGroupId}
                            musicBrainz={musicBrainz}
                            nativeSpotify={nativeSpotify}
                            qobuz={qobuz}
                            spotify={spotify}
                        />
                    </div>
                </div>
                {labels && (
                    <Stack gap="xs">
                        {labels.map((label) => (
                            <Text isMuted key={`label-${label}`} size="sm">
                                ℗{releaseYear ? ` ${releaseYear}` : ''} {label}
                            </Text>
                        ))}
                    </Stack>
                )}
                <AlbumDetailCarousels data={detailQuery?.data} />
            </div>
        </div>
    );
};

interface AlbumDetailSongsTableProps {
    songs: Song[];
}

interface DiscGroupRowProps {
    discGroup: {
        discNumber: number;
        discSubtitle: null | string;
    };
    groupItems: unknown[];
    internalState: ItemListStateActions;
    t: (key: string, options?: any) => string;
}

const DiscGroupRow = ({ discGroup, groupItems, internalState, t }: DiscGroupRowProps) => {
    const selectionVersion = useItemListStateSubscription(internalState, (state) =>
        state ? state.version : 0,
    );

    const selectedCount = groupItems.filter((item) => {
        if (!item || typeof item !== 'object' || !('id' in item)) return false;
        const rowId = internalState.extractRowId(item);
        return rowId ? internalState.isSelected(rowId) : false;
    }).length;

    const isAllSelected = selectedCount === groupItems.length;

    void selectionVersion;

    const handleCheckboxChange = () => {
        const selectableItems = groupItems.filter(
            (item): item is ItemListStateItemWithRequiredProperties =>
                item !== null && typeof item === 'object',
        );

        if (isAllSelected) {
            // Deselect all items in the group
            const currentlySelected =
                internalState.getSelected() as ItemListStateItemWithRequiredProperties[];
            const groupItemIds = new Set(
                selectableItems.map((item) => internalState.extractRowId(item)).filter(Boolean),
            );
            const itemsToKeep = currentlySelected.filter(
                (item) => !groupItemIds.has(internalState.extractRowId(item) || ''),
            );
            internalState.setSelected(itemsToKeep);
        } else {
            // Select all items in the group (add to existing selection)
            const currentlySelected =
                internalState.getSelected() as ItemListStateItemWithRequiredProperties[];
            const selectedIds = new Set(
                currentlySelected.map((item) => internalState.extractRowId(item)).filter(Boolean),
            );
            const itemsToAdd = selectableItems.filter(
                (item) => !selectedIds.has(internalState.extractRowId(item) || ''),
            );
            internalState.setSelected([...currentlySelected, ...itemsToAdd]);
        }
    };

    return (
        <Group align="center" h="100%" px="md" w="100%">
            <Checkbox
                checked={isAllSelected}
                id={`disc-${discGroup.discNumber}`}
                label={
                    <Text component="label" size="sm" truncate>
                        {t('common.disc')} {discGroup.discNumber}
                        {discGroup.discSubtitle && ` - ${discGroup.discSubtitle}`}
                    </Text>
                }
                onChange={handleCheckboxChange}
                size="xs"
            />
        </Group>
    );
};

function AlbumDetailCarousels({ data }: { data: Album }) {
    const { t } = useTranslation();

    const genreCarousels = useMemo(() => {
        const genreLimit = 2;
        const selectedGenres = data?.genres?.slice(0, genreLimit);

        if (!selectedGenres || selectedGenres.length === 0) return [];

        return selectedGenres
            .map((genre) => {
                const uniqueId = `moreFromGenre-${genre.id}`;
                return {
                    enableRefresh: true,
                    excludeIds: data?.id ? [data.id] : undefined,
                    isHidden: !genre,
                    query: {
                        genreIds: [genre.id],
                    },
                    rowCount: 1,
                    sortBy: AlbumListSort.RANDOM,
                    sortOrder: SortOrder.ASC,
                    title: sentenceCase(
                        t('page.albumDetail.moreFromGeneric', {
                            item: genre.name,
                        }),
                    ),
                    uniqueId,
                };
            })
            .filter((carousel) => !carousel.isHidden);
    }, [data, t]);

    const carousels = useMemo(() => {
        const moreFromArtistUniqueId = 'moreFromArtist';
        return [
            {
                enableRefresh: false,
                excludeIds: data?.id ? [data.id] : undefined,
                isHidden: !data?.albumArtists?.[0]?.id,
                query: {
                    artistIds: data?.albumArtists.length ? [data?.albumArtists[0].id] : undefined,
                },
                rowCount: 1,
                sortBy: AlbumListSort.YEAR,
                sortOrder: SortOrder.DESC,
                title: t('page.albumDetail.moreFromArtist'),
                uniqueId: moreFromArtistUniqueId,
            },
            ...genreCarousels,
        ];
    }, [data.albumArtists, data.id, genreCarousels, t]);

    const cq = useGridCarouselContainerQuery();

    return (
        <Stack gap="lg" mt="3rem" ref={cq.ref}>
            {carousels
                .filter((c) => !c.isHidden)
                .map((carousel) => (
                    <AlbumInfiniteCarousel
                        containerQuery={cq}
                        enableRefresh={carousel.enableRefresh}
                        excludeIds={carousel.excludeIds}
                        key={`carousel-${carousel.uniqueId}`}
                        query={carousel.query}
                        rowCount={carousel.rowCount}
                        sortBy={carousel.sortBy}
                        sortOrder={carousel.sortOrder}
                        title={carousel.title}
                    />
                ))}
        </Stack>
    );
}

const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
    const { t } = useTranslation();
    const [searchTerm, setSearchTerm] = useState('');
    const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
    const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.ALBUM_DETAIL]?.table);

    const currentSong = usePlayerSong();

    const [sortBy, setSortBy] = useState<SongListSort>(SongListSort.ID);
    const [sortOrder, setSortOrder] = useState<SortOrder>(SortOrder.ASC);

    const columns = useMemo(() => {
        return tableConfig?.columns || [];
    }, [tableConfig?.columns]);

    const filteredSongs = useMemo(() => {
        return sortSongList(
            searchLibraryItems(songs, debouncedSearchTerm, LibraryItem.SONG),
            sortBy,
            sortOrder,
        );
    }, [songs, debouncedSearchTerm, sortBy, sortOrder]);

    const { handleColumnReordered } = useItemListColumnReorder({
        itemListKey: ItemListKey.ALBUM_DETAIL,
    });

    const { handleColumnResized } = useItemListColumnResize({
        itemListKey: ItemListKey.ALBUM_DETAIL,
    });

    const discGroups = useMemo(() => {
        if (filteredSongs.length === 0) return [];

        const groups: Array<{
            discNumber: number;
            discSubtitle: null | string;
            itemCount: number;
        }> = [];
        let lastDiscNumber = -1;
        let currentGroupStartIndex = 0;

        filteredSongs.forEach((song, index) => {
            if (song.discNumber !== lastDiscNumber) {
                // If we have a previous group, calculate its item count
                if (groups.length > 0) {
                    groups[groups.length - 1].itemCount = index - currentGroupStartIndex;
                }
                // Start a new group
                groups.push({
                    discNumber: song.discNumber,
                    discSubtitle: song.discSubtitle,
                    itemCount: 0, // Will be calculated when we encounter the next group or end
                });
                currentGroupStartIndex = index;
                lastDiscNumber = song.discNumber;
            }
        });

        // Set item count for the last group
        if (groups.length > 0) {
            groups[groups.length - 1].itemCount = filteredSongs.length - currentGroupStartIndex;
        }

        return groups;
    }, [filteredSongs]);

    const groups = useMemo(() => {
        // Remove groups when filtering
        if (debouncedSearchTerm?.trim()) {
            return undefined;
        }

        // Remove groups when sorting
        if (sortBy !== SongListSort.ID) {
            return undefined;
        }

        if (discGroups.length <= 1) {
            return undefined;
        }

        return discGroups.map((discGroup) => ({
            itemCount: discGroup.itemCount,
            render: ({
                data,
                internalState,
                startDataIndex,
            }: {
                data: unknown[];
                groupIndex: number;
                index: number;
                internalState: ItemListStateActions;
                startDataIndex: number;
            }) => {
                const groupItems = data.slice(startDataIndex, startDataIndex + discGroup.itemCount);

                return (
                    <DiscGroupRow
                        discGroup={discGroup}
                        groupItems={groupItems}
                        internalState={internalState}
                        t={t}
                    />
                );
            },
            rowHeight: 40,
        }));
    }, [debouncedSearchTerm, sortBy, discGroups, t]);

    const player = usePlayer();

    const overrideControls: Partial<ItemControls> = useMemo(() => {
        return {
            onDoubleClick: ({ index, internalState, item, meta }) => {
                if (!item) {
                    return;
                }

                const playType = (meta?.playType as Play) || Play.NOW;

                const items = internalState?.getData() as Song[];

                if (index !== undefined) {
                    player.addToQueueByData(items, playType, item.id);
                }
            },
        };
    }, [player]);

    const binding = useSettingsStore((state) => state.hotkeys.bindings.localSearch);

    const searchInputRef = useRef<HTMLInputElement>(null);

    useHotkeys([
        [
            binding.hotkey,
            () => {
                searchInputRef.current?.focus();
            },
        ],
    ]);

    if (!tableConfig || columns.length === 0) {
        return null;
    }

    const currentSongId = currentSong?.id;

    return (
        <Stack gap="md">
            <Group gap="sm" w="100%">
                <TextInput
                    classNames={{ input: styles.searchTextInput }}
                    flex={1}
                    leftSection={<Icon icon="search" />}
                    onChange={(e) => setSearchTerm(e.target.value)}
                    placeholder={t('common.search')}
                    radius="xl"
                    ref={searchInputRef}
                    rightSection={
                        searchTerm ? (
                            <ActionIcon
                                icon="x"
                                onClick={() => setSearchTerm('')}
                                size="sm"
                                variant="transparent"
                            />
                        ) : null
                    }
                    value={searchTerm}
                />
                <ListSortByDropdownControlled
                    filters={CLIENT_SIDE_SONG_FILTERS}
                    itemType={LibraryItem.SONG}
                    setSortBy={(value) => setSortBy(value as SongListSort)}
                    sortBy={sortBy}
                />
                <ListSortOrderToggleButtonControlled
                    setSortOrder={(value) => setSortOrder(value as SortOrder)}
                    sortOrder={sortOrder}
                />
                <ListConfigMenu
                    displayTypes={[
                        { hidden: true, value: ListDisplayType.GRID },
                        ...SONG_DISPLAY_TYPES,
                    ]}
                    listKey={ItemListKey.ALBUM_DETAIL}
                    optionsConfig={{
                        table: {
                            itemsPerPage: { hidden: true },
                            pagination: { hidden: true },
                        },
                    }}
                    tableColumnsData={SONG_TABLE_COLUMNS}
                />
            </Group>
            <ItemTableList
                activeRowId={currentSongId}
                autoFitColumns={tableConfig.autoFitColumns}
                CellComponent={ItemTableListColumn}
                columns={columns}
                data={filteredSongs}
                enableAlternateRowColors={tableConfig.enableAlternateRowColors}
                enableDrag
                enableDragScroll={false}
                enableEntranceAnimation={false}
                enableExpansion={false}
                enableHeader={tableConfig.enableHeader}
                enableHorizontalBorders={tableConfig.enableHorizontalBorders}
                enableRowHoverHighlight={tableConfig.enableRowHoverHighlight}
                enableSelection
                enableSelectionDialog={false}
                enableStickyGroupRows
                enableStickyHeader
                enableVerticalBorders={tableConfig.enableVerticalBorders}
                groups={groups}
                itemType={LibraryItem.SONG}
                onColumnReordered={handleColumnReordered}
                onColumnResized={handleColumnResized}
                overrideControls={overrideControls}
                size={tableConfig.size}
            />
        </Stack>
    );
};
