import {
    useQuery,
    useQueryClient,
    useSuspenseQuery,
    UseSuspenseQueryResult,
} from '@tanstack/react-query';
import { motion } from 'motion/react';
import { memo, Suspense, useCallback, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { createSearchParams, generatePath, Link, useLocation, useParams } from 'react-router';

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

import { queryKeys } from '/@/renderer/api/query-keys';
import { DataRow, MemoizedItemCard } from '/@/renderer/components/item-card/item-card';
import { useDefaultItemListControls } from '/@/renderer/components/item-list/helpers/item-list-controls';
import { playSongFromItemListControl } from '/@/renderer/components/item-list/helpers/play-row-from-list';
import { useGridRows } from '/@/renderer/components/item-list/helpers/use-grid-rows';
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 { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
import { AlbumArtistGridCarousel } from '/@/renderer/features/artists/components/album-artist-grid-carousel';
import { useIsPlayerFetching, usePlayer } from '/@/renderer/features/player/context/player-context';
import {
    ListConfigMenu,
    SONG_DISPLAY_TYPES,
} from '/@/renderer/features/shared/components/list-config-menu';
import {
    CLIENT_SIDE_ALBUM_FILTERS,
    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 {
    LONG_PRESS_PLAY_BEHAVIOR,
    PlayTooltip,
} from '/@/renderer/features/shared/components/play-button-group';
import { usePlayButtonClick } from '/@/renderer/features/shared/hooks/use-play-button-click';
import { searchLibraryItems } from '/@/renderer/features/shared/utils';
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
import { useContainerQuery } from '/@/renderer/hooks';
import { useGenreRoute } from '/@/renderer/hooks/use-genre-route';
import { useHotkeys } from '/@/renderer/hooks/use-hotkeys';
import { AppRoute } from '/@/renderer/router/routes';
import {
    ArtistItem,
    useAppStore,
    useCurrentServer,
    useCurrentServerId,
    usePlayerSong,
    useShowFavorites,
    useShowRatings,
} from '/@/renderer/store';
import {
    useArtistItems,
    useArtistRadioCount,
    useExternalLinks,
    useSettingsStore,
} from '/@/renderer/store/settings.store';
import { sanitize } from '/@/renderer/utils/sanitize';
import { sortAlbumList, sortSongList } from '/@/shared/api/utils';
import { ActionIcon, ActionIconGroup } from '/@/shared/components/action-icon/action-icon';
import { Badge } from '/@/shared/components/badge/badge';
import { Button } from '/@/shared/components/button/button';
import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
import { Grid } from '/@/shared/components/grid/grid';
import { Group } from '/@/shared/components/group/group';
import { Icon } from '/@/shared/components/icon/icon';
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
import { Spinner } from '/@/shared/components/spinner/spinner';
import { Spoiler } from '/@/shared/components/spoiler/spoiler';
import { Stack } from '/@/shared/components/stack/stack';
import { TextInput } from '/@/shared/components/text-input/text-input';
import { TextTitle } from '/@/shared/components/text-title/text-title';
import { Text } from '/@/shared/components/text/text';
import { useDebouncedValue } from '/@/shared/hooks/use-debounced-value';
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
import {
    Album,
    AlbumArtist,
    AlbumArtistDetailResponse,
    AlbumListResponse,
    AlbumListSort,
    LibraryItem,
    RelatedArtist,
    ServerType,
    Song,
    SongListSort,
    SortOrder,
} from '/@/shared/types/domain-types';
import { ItemListKey, ListDisplayType, Play } from '/@/shared/types/types';

interface AlbumArtistActionButtonsProps {
    artistDiscographyLink: string;
    artistSongsLink: string;
    onArtistRadio?: () => void;
}

const AlbumArtistActionButtons = ({
    artistDiscographyLink,
    artistSongsLink,
    onArtistRadio,
}: AlbumArtistActionButtonsProps) => {
    const { t } = useTranslation();
    const isPlayerFetching = useIsPlayerFetching();

    return (
        <>
            <Group gap="lg">
                <Button
                    component={Link}
                    p={0}
                    size="compact-md"
                    to={artistDiscographyLink}
                    variant="transparent"
                >
                    {String(t('page.albumArtistDetail.viewDiscography')).toUpperCase()}
                </Button>
                <Button
                    component={Link}
                    p={0}
                    size="compact-md"
                    to={artistSongsLink}
                    variant="transparent"
                >
                    {String(t('page.albumArtistDetail.viewAllTracks')).toUpperCase()}
                </Button>
                {onArtistRadio && (
                    <Button
                        disabled={isPlayerFetching}
                        leftSection={
                            isPlayerFetching ? (
                                <Spinner color="white" size={16} />
                            ) : (
                                <Icon icon="radio" size="lg" />
                            )
                        }
                        onClick={onArtistRadio}
                        p={0}
                        size="compact-md"
                        variant="transparent"
                    >
                        {String(t('player.artistRadio')).toUpperCase()}
                    </Button>
                )}
            </Group>
        </>
    );
};

interface AlbumArtistMetadataGenresProps {
    genres?: Array<{ id: string; name: string }>;
    order?: number;
}

const AlbumArtistMetadataGenres = ({ genres, order }: AlbumArtistMetadataGenresProps) => {
    const { t } = useTranslation();
    const genrePath = useGenreRoute();

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

    return (
        <Grid.Col order={order} span={12}>
            <Stack gap="xs">
                <Text fw={600} isNoSelect size="sm" tt="uppercase">
                    {t('entity.genre', {
                        count: genres.length,
                    })}
                </Text>
                <Group gap="sm">
                    {genres.map((genre) => (
                        <Button
                            component={Link}
                            key={`genre-${genre.id}`}
                            radius="md"
                            size="compact-md"
                            to={generatePath(genrePath, {
                                albumArtistId: null,
                                albumId: null,
                                artistId: null,
                                genreId: genre.id,
                                itemType: null,
                                playlistId: null,
                            })}
                            variant="outline"
                        >
                            {genre.name}
                        </Button>
                    ))}
                </Group>
            </Stack>
        </Grid.Col>
    );
};

interface AlbumArtistMetadataBiographyProps {
    artistName?: string;
    order?: number;
    routeId: string;
}

const AlbumArtistMetadataBiography = ({
    artistName,
    order,
    routeId,
}: AlbumArtistMetadataBiographyProps) => {
    const { t } = useTranslation();
    const server = useCurrentServer();

    const artistInfoQuery = useQuery({
        ...artistsQueries.albumArtistInfo({
            query: { id: routeId, limit: 10 },
            serverId: server?.id,
        }),
        enabled: Boolean(server?.id && routeId),
    });

    const detailQuery = useQuery({
        ...artistsQueries.albumArtistDetail({
            query: { id: routeId },
            serverId: server?.id,
        }),
        enabled: Boolean(server?.id && routeId),
    });

    const biography = artistInfoQuery.data?.biography || detailQuery.data?.biography;
    const isLoading = !biography && (artistInfoQuery.isLoading || detailQuery.isLoading);

    const sanitizedBiography = biography ? sanitize(biography) : '';

    if (isLoading) {
        return (
            <Grid.Col order={order} span={12}>
                <section style={{ maxWidth: '1280px' }}>
                    <TextTitle fw={700} order={3}>
                        {t('page.albumArtistDetail.about', {
                            artist: artistName,
                        })}
                    </TextTitle>
                    <Stack gap="xs">
                        <Skeleton enableAnimation height="1rem" width="100%" />
                        <Skeleton enableAnimation height="1rem" width="98%" />
                        <Skeleton enableAnimation height="1rem" width="60%" />
                    </Stack>
                </section>
            </Grid.Col>
        );
    }

    if (!biography) {
        return null;
    }

    return (
        <Grid.Col order={order} span={12}>
            <section style={{ maxWidth: '1280px' }}>
                <TextTitle fw={700} order={3}>
                    {t('page.albumArtistDetail.about', {
                        artist: artistName,
                    })}
                </TextTitle>
                <Spoiler>
                    <Text dangerouslySetInnerHTML={{ __html: sanitizedBiography }} />
                </Spoiler>
            </section>
        </Grid.Col>
    );
};

const TABLE_ROW_HEIGHT = {
    compact: 40,
    default: 64,
    large: 88,
} as const;

const TABLE_HEADER_HEIGHT = 40;

interface SongTableListContainerProps {
    children: React.ReactNode;
    enableHeader?: boolean;
    itemCount: number;
    maxRows?: number;
    tableSize?: 'compact' | 'default' | 'large';
}

function getTableRowHeight(size: 'compact' | 'default' | 'large' | undefined): number {
    return size ? TABLE_ROW_HEIGHT[size] : TABLE_ROW_HEIGHT.default;
}

const SongTableListContainer = ({
    children,
    enableHeader = true,
    itemCount,
    maxRows = 5,
    tableSize = 'default',
}: SongTableListContainerProps) => {
    const rowHeight = getTableRowHeight(tableSize);
    const headerOffset = enableHeader ? TABLE_HEADER_HEIGHT : 0;
    const height = headerOffset + rowHeight * Math.min(itemCount, maxRows);
    return <div style={{ height }}>{children}</div>;
};

interface AlbumArtistMetadataTopSongsProps {
    detailQuery: ReturnType<typeof useSuspenseQuery<AlbumArtistDetailResponse>>;
    order?: number;
    routeId: string;
}

const AlbumArtistMetadataTopSongsContent = ({
    detailQuery,
    order,
    routeId,
}: AlbumArtistMetadataTopSongsProps) => {
    const { t } = useTranslation();
    const [searchTerm, setSearchTerm] = useState('');
    const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
    const [topSongsQueryType, setTopSongsQueryType] = useLocalStorage<'community' | 'personal'>({
        defaultValue: 'community',
        key: 'album-artist-top-songs-query-type',
    });
    const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.SONG]?.table);
    const currentSong = usePlayerSong();
    const player = usePlayer();
    const serverId = useCurrentServerId();
    const server = useCurrentServer();

    const canStartQuery = server?.type === ServerType.JELLYFIN || !!detailQuery.data?.name;

    const topSongsQuery = useQuery({
        ...artistsQueries.topSongs({
            query: {
                artist: detailQuery.data?.name || '',
                artistId: routeId,
                type: topSongsQueryType,
            },
            serverId: serverId,
        }),
        enabled: canStartQuery,
    });

    const songs = useMemo(() => topSongsQuery.data?.items || [], [topSongsQuery.data?.items]);

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

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

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

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

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

                playSongFromItemListControl({
                    index,
                    internalState,
                    item: item as Song,
                    meta,
                    player,
                });
            },
        };
    }, [player]);

    const handlePlay = useCallback(
        (playType: Play) => {
            if (songs.length === 0) return;
            player.addToQueueByData(songs, playType);
        },
        [songs, player],
    );

    const handlePlayNext = usePlayButtonClick({
        onClick: () => handlePlay(Play.NEXT),
        onLongPress: () => handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.NEXT]),
    });
    const handlePlayNow = usePlayButtonClick({
        onClick: () => handlePlay(Play.NOW),
        onLongPress: () => handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.NOW]),
    });
    const handlePlayLast = usePlayButtonClick({
        onClick: () => handlePlay(Play.LAST),
        onLongPress: () => handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.LAST]),
    });

    const isLoading = topSongsQuery.isLoading || !topSongsQuery.data;

    if (!isLoading && !tableConfig) return null;
    if (!isLoading && songs.length === 0) return null;

    const currentSongId = currentSong?.id;

    return (
        <Grid.Col order={order} span={12}>
            <section>
                <Stack gap="md">
                    <div className={styles.albumSectionTitle}>
                        <Group>
                            <TextTitle fw={700} order={3}>
                                {t('page.albumArtistDetail.topSongs')}
                            </TextTitle>
                            {!isLoading && <Badge>{songs.length}</Badge>}
                        </Group>
                        <div className={styles.albumSectionDividerContainer}>
                            <div className={styles.albumSectionDivider} />
                            <Button
                                component={Link}
                                size="compact-md"
                                to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_TOP_SONGS, {
                                    albumArtistId: routeId,
                                })}
                                uppercase
                                variant="subtle"
                            >
                                {t('page.albumArtistDetail.viewAll')}
                            </Button>
                            {songs.length > 0 && (
                                <ActionIconGroup>
                                    <PlayTooltip type={Play.NOW}>
                                        <ActionIcon
                                            icon="mediaPlay"
                                            iconProps={{ size: 'md' }}
                                            size="xs"
                                            variant="subtle"
                                            {...handlePlayNow.handlers}
                                            {...handlePlayNow.props}
                                            disabled={isLoading}
                                        />
                                    </PlayTooltip>
                                    <PlayTooltip type={Play.NEXT}>
                                        <ActionIcon
                                            icon="mediaPlayNext"
                                            iconProps={{ size: 'md' }}
                                            size="xs"
                                            variant="subtle"
                                            {...handlePlayNext.handlers}
                                            {...handlePlayNext.props}
                                            disabled={isLoading}
                                        />
                                    </PlayTooltip>
                                    <PlayTooltip type={Play.LAST}>
                                        <ActionIcon
                                            icon="mediaPlayLast"
                                            iconProps={{ size: 'md' }}
                                            size="xs"
                                            variant="subtle"
                                            {...handlePlayLast.handlers}
                                            {...handlePlayLast.props}
                                            disabled={isLoading}
                                        />
                                    </PlayTooltip>
                                </ActionIconGroup>
                            )}
                        </div>
                    </div>
                    {isLoading ? (
                        <Group justify="center" py="md">
                            <Spinner container />
                        </Group>
                    ) : tableConfig ? (
                        <>
                            <Group gap="sm" w="100%">
                                <TextInput
                                    flex={1}
                                    leftSection={<Icon icon="search" />}
                                    onChange={(e) => setSearchTerm(e.target.value)}
                                    placeholder={t('common.search')}
                                    radius="xl"
                                    rightSection={
                                        searchTerm ? (
                                            <ActionIcon
                                                icon="x"
                                                onClick={() => setSearchTerm('')}
                                                size="sm"
                                                variant="transparent"
                                            />
                                        ) : null
                                    }
                                    styles={{
                                        input: {
                                            background: 'transparent',
                                            border: '1px solid rgba(255, 255, 255, 0.05)',
                                        },
                                    }}
                                    value={searchTerm}
                                />
                                <SegmentedControl
                                    data={[
                                        {
                                            label: t('page.albumArtistDetail.topSongsCommunity'),
                                            value: 'community',
                                        },
                                        {
                                            label: t('page.albumArtistDetail.topSongsPersonal'),
                                            value: 'personal',
                                        },
                                    ]}
                                    onChange={(value) =>
                                        setTopSongsQueryType(value as 'community' | 'personal')
                                    }
                                    size="xs"
                                    value={topSongsQueryType}
                                />
                                <ListConfigMenu
                                    displayTypes={[
                                        { hidden: true, value: ListDisplayType.GRID },
                                        ...SONG_DISPLAY_TYPES,
                                    ]}
                                    listKey={ItemListKey.SONG}
                                    optionsConfig={{
                                        table: {
                                            itemsPerPage: { hidden: true },
                                            pagination: { hidden: true },
                                        },
                                    }}
                                    tableColumnsData={SONG_TABLE_COLUMNS}
                                />
                            </Group>
                            <SongTableListContainer
                                enableHeader={tableConfig.enableHeader}
                                itemCount={filteredSongs.length}
                                maxRows={5}
                                tableSize={tableConfig.size}
                            >
                                <ItemTableList
                                    activeRowId={currentSongId}
                                    autoFitColumns={tableConfig.autoFitColumns}
                                    CellComponent={ItemTableListColumn}
                                    columns={columns}
                                    data={filteredSongs}
                                    enableAlternateRowColors={tableConfig.enableAlternateRowColors}
                                    enableDrag
                                    enableDragScroll={false}
                                    enableExpansion={false}
                                    enableHeader={tableConfig.enableHeader}
                                    enableHorizontalBorders={tableConfig.enableHorizontalBorders}
                                    enableRowHoverHighlight={tableConfig.enableRowHoverHighlight}
                                    enableSelection
                                    enableSelectionDialog={false}
                                    enableVerticalBorders={tableConfig.enableVerticalBorders}
                                    itemType={LibraryItem.SONG}
                                    onColumnReordered={handleColumnReordered}
                                    onColumnResized={handleColumnResized}
                                    overrideControls={overrideControls}
                                    size={tableConfig.size}
                                />
                            </SongTableListContainer>
                        </>
                    ) : null}
                </Stack>
            </section>
        </Grid.Col>
    );
};

const AlbumArtistMetadataTopSongs = ({
    detailQuery,
    order,
    routeId,
}: AlbumArtistMetadataTopSongsProps) => {
    const server = useCurrentServer();

    const location = useLocation();
    const artistName = location.state?.item?.name || detailQuery.data?.name;

    const canStartQuery = server?.type === ServerType.JELLYFIN || !!artistName;

    return (
        <Suspense fallback={null}>
            {canStartQuery ? (
                <AlbumArtistMetadataTopSongsContent
                    detailQuery={detailQuery}
                    order={order}
                    routeId={routeId}
                />
            ) : null}
        </Suspense>
    );
};

interface AlbumArtistMetadataFavoriteSongsProps {
    order?: number;
    routeId: string;
}

const AlbumArtistMetadataFavoriteSongs = ({
    order,
    routeId,
}: AlbumArtistMetadataFavoriteSongsProps) => {
    const { t } = useTranslation();
    const [searchTerm, setSearchTerm] = useState('');
    const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
    const [favoriteSongsQueryType, setFavoriteSongsQueryType] = useLocalStorage<
        'favorite' | 'rating'
    >({
        defaultValue: 'favorite',
        key: 'album-artist-favorite-songs-query-type',
    });
    const albumArtistDetailFavoriteSongsSort = useAppStore(
        (state) => state.albumArtistDetailFavoriteSongsSort,
    );
    const setAlbumArtistDetailFavoriteSongsSort = useAppStore(
        (state) => state.actions.setAlbumArtistDetailFavoriteSongsSort,
    );
    const sortBy = albumArtistDetailFavoriteSongsSort.sortBy;
    const sortOrder = albumArtistDetailFavoriteSongsSort.sortOrder;
    const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.SONG]?.table);
    const currentSong = usePlayerSong();
    const player = usePlayer();
    const serverId = useCurrentServerId();
    const server = useCurrentServer();
    const showRatings = useShowRatings();
    const showFavorites = useShowFavorites();
    const showFavoriteAndRatingSegmentControl =
        server?.type !== ServerType.JELLYFIN && showFavorites && showRatings;

    let favoriteSongsQueryTypeFilter = favoriteSongsQueryType;
    if (showRatings && !showFavorites) {
        favoriteSongsQueryTypeFilter = 'rating';
    } else if (!showRatings && showFavorites) {
        favoriteSongsQueryTypeFilter = 'favorite';
    }

    const favoriteSongsQuery = useQuery({
        ...artistsQueries.favoriteSongs({
            query: {
                artistId: routeId,
                type: favoriteSongsQueryTypeFilter,
            },
            serverId: serverId,
        }),
    });

    const songs = useMemo(
        () => favoriteSongsQuery.data?.items || [],
        [favoriteSongsQuery.data?.items],
    );

    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.SONG,
    });

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

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

                playSongFromItemListControl({
                    index,
                    internalState,
                    item: item as Song,
                    meta,
                    player,
                });
            },
        };
    }, [player]);

    const handlePlay = useCallback(
        (playType: Play) => {
            if (songs.length === 0) return;
            player.addToQueueByData(songs, playType);
        },
        [songs, player],
    );

    const handlePlayNext = usePlayButtonClick({
        onClick: () => handlePlay(Play.NEXT),
        onLongPress: () => handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.NEXT]),
    });
    const handlePlayNow = usePlayButtonClick({
        onClick: () => handlePlay(Play.NOW),
        onLongPress: () => handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.NOW]),
    });
    const handlePlayLast = usePlayButtonClick({
        onClick: () => handlePlay(Play.LAST),
        onLongPress: () => handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.LAST]),
    });

    const isLoading = favoriteSongsQuery.isLoading || !favoriteSongsQuery.data;

    if (!isLoading && !tableConfig) return null;
    if (!isLoading && songs.length === 0) return null;

    const currentSongId = currentSong?.id;

    return (
        <Grid.Col order={order} span={12}>
            <section>
                <Stack gap="md">
                    <div className={styles.albumSectionTitle}>
                        <Group>
                            <TextTitle fw={700} order={3}>
                                {t('page.albumArtistDetail.favoriteSongs')}
                            </TextTitle>
                            {!isLoading && <Badge>{songs.length}</Badge>}
                        </Group>
                        <div className={styles.albumSectionDividerContainer}>
                            <div className={styles.albumSectionDivider} />
                            <Button
                                component={Link}
                                size="compact-md"
                                to={generatePath(
                                    AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_FAVORITE_SONGS,
                                    {
                                        albumArtistId: routeId,
                                    },
                                )}
                                uppercase
                                variant="subtle"
                            >
                                {t('page.albumArtistDetail.viewAll')}
                            </Button>
                            {songs.length > 0 && (
                                <ActionIconGroup>
                                    <PlayTooltip type={Play.NOW}>
                                        <ActionIcon
                                            icon="mediaPlay"
                                            iconProps={{ size: 'md' }}
                                            size="xs"
                                            variant="subtle"
                                            {...handlePlayNow.handlers}
                                            {...handlePlayNow.props}
                                            disabled={isLoading}
                                        />
                                    </PlayTooltip>
                                    <PlayTooltip type={Play.NEXT}>
                                        <ActionIcon
                                            icon="mediaPlayNext"
                                            iconProps={{ size: 'md' }}
                                            size="xs"
                                            variant="subtle"
                                            {...handlePlayNext.handlers}
                                            {...handlePlayNext.props}
                                            disabled={isLoading}
                                        />
                                    </PlayTooltip>
                                    <PlayTooltip type={Play.LAST}>
                                        <ActionIcon
                                            icon="mediaPlayLast"
                                            iconProps={{ size: 'md' }}
                                            size="xs"
                                            variant="subtle"
                                            {...handlePlayLast.handlers}
                                            {...handlePlayLast.props}
                                            disabled={isLoading}
                                        />
                                    </PlayTooltip>
                                </ActionIconGroup>
                            )}
                        </div>
                    </div>
                    {isLoading ? (
                        <Group justify="center" py="md">
                            <Spinner />
                        </Group>
                    ) : tableConfig ? (
                        <>
                            <Group gap="sm" w="100%">
                                <TextInput
                                    flex={1}
                                    leftSection={<Icon icon="search" />}
                                    onChange={(e) => setSearchTerm(e.target.value)}
                                    placeholder={t('common.search')}
                                    radius="xl"
                                    rightSection={
                                        searchTerm ? (
                                            <ActionIcon
                                                icon="x"
                                                onClick={() => setSearchTerm('')}
                                                size="sm"
                                                variant="transparent"
                                            />
                                        ) : null
                                    }
                                    styles={{
                                        input: {
                                            background: 'transparent',
                                            border: '1px solid rgba(255, 255, 255, 0.05)',
                                        },
                                    }}
                                    value={searchTerm}
                                />
                                {showFavoriteAndRatingSegmentControl && (
                                    <SegmentedControl
                                        data={[
                                            {
                                                label: t('common.favorite'),
                                                value: 'favorite',
                                            },
                                            {
                                                label: t('common.rating'),
                                                value: 'rating',
                                            },
                                        ]}
                                        onChange={(value) =>
                                            setFavoriteSongsQueryType(
                                                value as 'favorite' | 'rating',
                                            )
                                        }
                                        size="xs"
                                        value={favoriteSongsQueryType}
                                    />
                                )}
                                <ListSortByDropdownControlled
                                    filters={CLIENT_SIDE_SONG_FILTERS}
                                    itemType={LibraryItem.SONG}
                                    setSortBy={(value) =>
                                        setAlbumArtistDetailFavoriteSongsSort(
                                            value as SongListSort,
                                            sortOrder,
                                        )
                                    }
                                    sortBy={sortBy}
                                />
                                <ListSortOrderToggleButtonControlled
                                    setSortOrder={(value) =>
                                        setAlbumArtistDetailFavoriteSongsSort(
                                            sortBy,
                                            value as SortOrder,
                                        )
                                    }
                                    sortOrder={sortOrder}
                                />
                                <ListConfigMenu
                                    displayTypes={[
                                        { hidden: true, value: ListDisplayType.GRID },
                                        ...SONG_DISPLAY_TYPES,
                                    ]}
                                    listKey={ItemListKey.SONG}
                                    optionsConfig={{
                                        table: {
                                            itemsPerPage: { hidden: true },
                                            pagination: { hidden: true },
                                        },
                                    }}
                                    tableColumnsData={SONG_TABLE_COLUMNS}
                                />
                            </Group>
                            <SongTableListContainer
                                enableHeader={tableConfig.enableHeader}
                                itemCount={filteredSongs.length}
                                maxRows={5}
                                tableSize={tableConfig.size}
                            >
                                <ItemTableList
                                    activeRowId={currentSongId}
                                    autoFitColumns={tableConfig.autoFitColumns}
                                    CellComponent={ItemTableListColumn}
                                    columns={columns}
                                    data={filteredSongs}
                                    enableAlternateRowColors={tableConfig.enableAlternateRowColors}
                                    enableDrag
                                    enableDragScroll={false}
                                    enableExpansion={false}
                                    enableHeader={tableConfig.enableHeader}
                                    enableHorizontalBorders={tableConfig.enableHorizontalBorders}
                                    enableRowHoverHighlight={tableConfig.enableRowHoverHighlight}
                                    enableSelection
                                    enableSelectionDialog={false}
                                    enableVerticalBorders={tableConfig.enableVerticalBorders}
                                    itemType={LibraryItem.SONG}
                                    onColumnReordered={handleColumnReordered}
                                    onColumnResized={handleColumnResized}
                                    overrideControls={overrideControls}
                                    size={tableConfig.size}
                                />
                            </SongTableListContainer>
                        </>
                    ) : null}
                </Stack>
            </section>
        </Grid.Col>
    );
};

interface AlbumArtistMetadataExternalLinksProps {
    artistName?: string;
    externalLinks: boolean;
    lastFM: boolean;
    listenBrainz: boolean;
    mbzId?: null | string;
    musicBrainz: boolean;
    nativeSpotify: boolean;
    order?: number;
    qobuz: boolean;
    spotify: boolean;
}

const getListenBrainzUrl = (mbzId: null | string, artistName?: string) => {
    if (mbzId) {
        return `https://listenbrainz.org/artist/${mbzId}`;
    }

    if (artistName) {
        return `https://listenbrainz.org/search/?search_term=${encodeURIComponent(artistName)}`;
    }

    return null;
};

const getQobuzUrl = (artistName?: string) => {
    if (artistName) {
        return `https://www.qobuz.com/us-en/search/artists/${encodeURIComponent(artistName)}`;
    }

    return null;
};

const AlbumArtistMetadataExternalLinks = ({
    artistName,
    externalLinks,
    lastFM,
    listenBrainz,
    mbzId,
    musicBrainz,
    nativeSpotify,
    order,
    qobuz,
    spotify,
}: AlbumArtistMetadataExternalLinksProps) => {
    const { t } = useTranslation();
    const listenBrainzUrl = getListenBrainzUrl(mbzId || null, artistName);
    const qobuzUrl = getQobuzUrl(artistName);

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

    return (
        <Grid.Col order={order} span={12}>
            <Stack gap="xs">
                <Text fw={600} isNoSelect size="sm" tt="uppercase">
                    {t('common.externalLinks')}
                </Text>
                <Group gap="xs">
                    {lastFM && (
                        <ActionIcon
                            component="a"
                            href={`https://www.last.fm/music/${encodeURIComponent(artistName || '')}`}
                            icon="brandLastfm"
                            iconProps={{
                                size: '2xl',
                            }}
                            rel="noopener noreferrer"
                            target="_blank"
                            tooltip={{
                                label: t('action.openIn.lastfm'),
                            }}
                            variant="subtle"
                        />
                    )}
                    {mbzId && musicBrainz ? (
                        <ActionIcon
                            component="a"
                            href={`https://musicbrainz.org/artist/${mbzId}`}
                            icon="brandMusicBrainz"
                            iconProps={{
                                size: '2xl',
                            }}
                            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',
                            }}
                            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',
                            }}
                            rel="noopener noreferrer"
                            target="_blank"
                            tooltip={{
                                label: t('action.openIn.qobuz'),
                            }}
                            variant="subtle"
                        />
                    )}
                    {spotify && (
                        <ActionIcon
                            component="a"
                            href={
                                nativeSpotify
                                    ? `spotify:search:${encodeURIComponent(artistName || '')}`
                                    : `https://open.spotify.com/search/${encodeURIComponent(artistName || '')}`
                            }
                            icon="brandSpotify"
                            iconProps={{
                                size: '2xl',
                            }}
                            rel="noopener noreferrer"
                            target={nativeSpotify ? undefined : '_blank'}
                            tooltip={{
                                label: t('action.openIn.spotify'),
                            }}
                            variant="subtle"
                        />
                    )}
                </Group>
            </Stack>
        </Grid.Col>
    );
};

interface AlbumArtistMetadataSimilarArtistsProps {
    order?: number;
    routeId: string;
}

const AlbumArtistMetadataSimilarArtists = ({
    order,
    routeId,
}: AlbumArtistMetadataSimilarArtistsProps) => {
    const { t } = useTranslation();
    const server = useCurrentServer();
    const serverId = useCurrentServerId();

    const artistInfoQuery = useQuery({
        ...artistsQueries.albumArtistInfo({
            query: { id: routeId, limit: 10 },
            serverId: server?.id,
        }),
        enabled: Boolean(server?.id && routeId),
    });

    const relatedArtists = artistInfoQuery.data?.similarArtists ?? null;

    const similarArtists = useMemo(() => {
        if (!relatedArtists || relatedArtists.length === 0) {
            return [];
        }

        return relatedArtists.map(
            (relatedArtist: RelatedArtist): AlbumArtist => ({
                _itemType: LibraryItem.ALBUM_ARTIST,
                _serverId: serverId || '',
                _serverType: (server?.type as ServerType) || ServerType.JELLYFIN,
                albumCount: null,
                biography: null,
                duration: null,
                genres: [],
                id: relatedArtist.id,
                imageId: relatedArtist.imageId,
                imageUrl: relatedArtist.imageUrl,
                lastPlayedAt: null,
                mbz: null,
                name: relatedArtist.name,
                playCount: null,
                similarArtists: null,
                songCount: null,
                userFavorite: relatedArtist.userFavorite,
                userRating: relatedArtist.userRating,
            }),
        );
    }, [relatedArtists, server?.type, serverId]);

    const carouselTitle = useMemo(
        () => (
            <div className={styles.similarArtistsTitle}>
                <TextTitle fw={700} order={3}>
                    {t('page.albumArtistDetail.relatedArtists')}
                </TextTitle>
                <div className={styles.albumSectionDividerContainer}>
                    <div className={styles.albumSectionDivider} />
                </div>
            </div>
        ),
        [t],
    );

    if (!artistInfoQuery.isLoading && similarArtists.length === 0) {
        return null;
    }

    return (
        <Grid.Col order={order} span={12}>
            <AlbumArtistGridCarousel
                data={similarArtists}
                excludeIds={[routeId]}
                isLoading={artistInfoQuery.isLoading}
                rowCount={1}
                title={carouselTitle}
            />
        </Grid.Col>
    );
};

interface AlbumArtistDetailContentProps {
    albumsQuery: UseSuspenseQueryResult<AlbumListResponse, Error>;
    detailQuery: UseSuspenseQueryResult<AlbumArtistDetailResponse, Error>;
}

export const AlbumArtistDetailContent = ({
    albumsQuery,
    detailQuery,
}: AlbumArtistDetailContentProps) => {
    const artistItems = useArtistItems();
    const artistRadioCount = useArtistRadioCount();
    const { externalLinks, lastFM, listenBrainz, musicBrainz, nativeSpotify, qobuz, spotify } =
        useExternalLinks();
    const { albumArtistId, artistId } = useParams() as {
        albumArtistId?: string;
        artistId?: string;
    };
    const routeId = (artistId || albumArtistId) as string;
    const server = useCurrentServer();
    const { addToQueueByData } = usePlayer();
    const queryClient = useQueryClient();

    const [enabledItem, itemOrder] = useMemo(() => {
        const enabled: { [key in ArtistItem]?: boolean } = {};
        const order: { [key in ArtistItem]?: number } = {};

        for (const [idx, item] of artistItems.entries()) {
            enabled[item.id] = !item.disabled;
            order[item.id] = idx + 1;
        }

        return [enabled, order];
    }, [artistItems]);

    const artistDiscographyLink = useMemo(
        () =>
            `${generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_DISCOGRAPHY, {
                albumArtistId: routeId,
            })}?${createSearchParams({
                artistId: routeId,
                artistName: detailQuery.data?.name || '',
            })}`,
        [routeId, detailQuery.data?.name],
    );

    const artistSongsLink = useMemo(
        () =>
            `${generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_SONGS, {
                albumArtistId: routeId,
            })}?${createSearchParams({
                artistId: routeId,
                artistName: detailQuery.data?.name || '',
            })}`,
        [routeId, detailQuery.data?.name],
    );

    const mbzId = detailQuery.data?.mbz;

    const handleArtistRadio = useCallback(async () => {
        if (!server?.id || !routeId) return;

        try {
            const artistRadioSongs = await queryClient.fetchQuery({
                ...songsQueries.artistRadio({
                    query: {
                        artistId: routeId,
                        count: artistRadioCount,
                    },
                    serverId: server.id,
                }),
                queryKey: queryKeys.player.fetch({ artistId: routeId }),
            });
            if (artistRadioSongs && artistRadioSongs.length > 0) {
                addToQueueByData(artistRadioSongs, Play.NOW);
            }
        } catch (error) {
            console.error('Failed to load artist radio:', error);
        }
    }, [addToQueueByData, artistRadioCount, queryClient, routeId, server.id]);

    // Calculate order for genres and external links (show before other sections)
    // Use a very low order number to ensure they appear first
    const genresOrder = 0;
    const externalLinksOrder = 0.5;

    return (
        <div className={styles.contentContainer}>
            <div className={styles.detailContainer}>
                <AlbumArtistActionButtons
                    artistDiscographyLink={artistDiscographyLink}
                    artistSongsLink={artistSongsLink}
                    onArtistRadio={handleArtistRadio}
                />
                <Grid gap="2xl">
                    <AlbumArtistMetadataGenres
                        genres={detailQuery.data?.genres}
                        order={genresOrder}
                    />
                    {externalLinks &&
                        (lastFM || listenBrainz || musicBrainz || qobuz || spotify) && (
                            <AlbumArtistMetadataExternalLinks
                                artistName={detailQuery.data?.name}
                                externalLinks={externalLinks}
                                lastFM={lastFM}
                                listenBrainz={listenBrainz}
                                mbzId={mbzId}
                                musicBrainz={musicBrainz}
                                nativeSpotify={nativeSpotify}
                                order={externalLinksOrder}
                                qobuz={qobuz}
                                spotify={spotify}
                            />
                        )}
                    {enabledItem.biography && (
                        <AlbumArtistMetadataBiography
                            artistName={detailQuery.data?.name}
                            order={itemOrder.biography}
                            routeId={routeId}
                        />
                    )}
                    <ArtistAlbums albumsQuery={albumsQuery} order={itemOrder.recentAlbums} />
                    {enabledItem.similarArtists && (
                        <AlbumArtistMetadataSimilarArtists
                            order={itemOrder.similarArtists}
                            routeId={routeId}
                        />
                    )}
                    {enabledItem.topSongs && (
                        <AlbumArtistMetadataTopSongs
                            detailQuery={detailQuery}
                            order={itemOrder.topSongs}
                            routeId={routeId}
                        />
                    )}
                    {enabledItem.favoriteSongs && (
                        <AlbumArtistMetadataFavoriteSongs
                            order={itemOrder.favoriteSongs}
                            routeId={routeId}
                        />
                    )}
                </Grid>
            </div>
        </div>
    );
};

interface AlbumSectionProps {
    albums: Album[];
    controls: ItemControls;
    enableExpansion?: boolean;
    itemsPerRow: number;
    releaseType: string;
    rows: DataRow[] | undefined;
    title: React.ReactNode | string;
}

const MAX_SECTION_CARDS = 100;

const getItemsPerRow = (cq: ReturnType<typeof useContainerQuery>) => {
    // Match grid carousel breakpoints: is3xl: 8, is2xl: 7, isXl: 6, isLg: 5, isMd: 4, isSm: 3, default: 2
    if (cq.is3xl) return 8;
    if (cq.is2xl) return 7;
    if (cq.isXl) return 6;
    if (cq.isLg) return 5;
    if (cq.isMd) return 4;
    if (cq.isSm) return 3;
    if (cq.isXs) return 2;
    return 2;
};

const AlbumSection = memo(function AlbumSection({
    albums,
    controls,
    enableExpansion,
    itemsPerRow,
    releaseType,
    rows,
    title,
}: AlbumSectionProps) {
    const { t } = useTranslation();
    const albumCount = albums.length;
    const [showAll, setShowAll] = useState(false);
    const player = usePlayer();
    const serverId = useCurrentServerId();

    const displayedAlbums = showAll ? albums : albums.slice(0, MAX_SECTION_CARDS);
    const hasMoreAlbums = albums.length > MAX_SECTION_CARDS;

    const handlePlay = useCallback(
        (playType: Play) => {
            if (albums.length === 0) return;
            const albumIds = albums.map((album) => album.id);
            player.addToQueueByFetch(serverId, albumIds, LibraryItem.ALBUM, playType);
        },
        [albums, player, serverId],
    );

    const handlePlayNext = usePlayButtonClick({
        onClick: () => {
            handlePlay(Play.NEXT);
        },
        onLongPress: () => {
            handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.NEXT]);
        },
    });

    const handlePlayNow = usePlayButtonClick({
        onClick: () => {
            handlePlay(Play.NOW);
        },
        onLongPress: () => {
            handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.NOW]);
        },
    });

    const handlePlayLast = usePlayButtonClick({
        onClick: () => {
            handlePlay(Play.LAST);
        },
        onLongPress: () => {
            handlePlay(LONG_PRESS_PLAY_BEHAVIOR[Play.LAST]);
        },
    });

    const DisplayedAlbumsMemo = useMemo(() => {
        return displayedAlbums.map((album) => (
            <motion.div
                className={styles.albumGridItem}
                key={album.id}
                layoutId={`${releaseType}-${album.id}`}
            >
                <MemoizedItemCard
                    controls={controls}
                    data={album}
                    enableDrag
                    enableExpansion={enableExpansion ?? true}
                    itemType={LibraryItem.ALBUM}
                    rows={rows}
                    type="poster"
                    withControls
                />
            </motion.div>
        ));
    }, [controls, displayedAlbums, enableExpansion, releaseType, rows]);

    return (
        <Stack gap="md">
            <div className={styles.albumSectionTitle}>
                <Group gap="md">
                    <TextTitle fw={700} order={3}>
                        {title}
                    </TextTitle>
                    <Badge variant="default">{albumCount}</Badge>
                </Group>
                <div className={styles.albumSectionDividerContainer}>
                    <div className={styles.albumSectionDivider} />
                    {albumCount > 0 && (
                        <ActionIconGroup>
                            <PlayTooltip type={Play.NOW}>
                                <ActionIcon
                                    icon="mediaPlay"
                                    iconProps={{
                                        size: 'md',
                                    }}
                                    size="xs"
                                    variant="subtle"
                                    {...handlePlayNow.handlers}
                                    {...handlePlayNow.props}
                                />
                            </PlayTooltip>
                            <PlayTooltip type={Play.NEXT}>
                                <ActionIcon
                                    icon="mediaPlayNext"
                                    iconProps={{
                                        size: 'md',
                                    }}
                                    size="xs"
                                    variant="subtle"
                                    {...handlePlayNext.handlers}
                                    {...handlePlayNext.props}
                                />
                            </PlayTooltip>
                            <PlayTooltip type={Play.LAST}>
                                <ActionIcon
                                    icon="mediaPlayLast"
                                    iconProps={{
                                        size: 'md',
                                    }}
                                    size="xs"
                                    variant="subtle"
                                    {...handlePlayLast.handlers}
                                    {...handlePlayLast.props}
                                />
                            </PlayTooltip>
                        </ActionIconGroup>
                    )}
                </div>
            </div>
            <div
                className={styles.albumGrid}
                style={
                    {
                        '--items-per-row': itemsPerRow,
                    } as React.CSSProperties
                }
            >
                {DisplayedAlbumsMemo}
            </div>
            {hasMoreAlbums && !showAll && (
                <Group justify="center" w="100%">
                    <Button onClick={() => setShowAll(true)} variant="subtle">
                        {t('action.viewMore')}
                    </Button>
                </Group>
            )}
        </Stack>
    );
});

import { useArtistAlbumsGrouped } from '/@/renderer/features/artists/hooks/use-artist-albums-grouped';

interface ArtistAlbumsProps {
    albumsQuery: UseSuspenseQueryResult<AlbumListResponse, Error>;
    order?: number;
}

const ArtistAlbums = ({ albumsQuery, order }: ArtistAlbumsProps) => {
    const { t } = useTranslation();
    const [searchTerm, setSearchTerm] = useState('');
    const [debouncedSearchTerm] = useDebouncedValue(searchTerm, 300);
    const albumArtistDetailSort = useAppStore((state) => state.albumArtistDetailSort);
    const setAlbumArtistDetailSort = useAppStore((state) => state.actions.setAlbumArtistDetailSort);
    const sortBy = albumArtistDetailSort.sortBy;
    const sortOrder = albumArtistDetailSort.sortOrder;

    const { albumArtistId, artistId } = useParams() as {
        albumArtistId?: string;
        artistId?: string;
    };
    const routeId = (artistId || albumArtistId) as string;

    const rows = useGridRows(LibraryItem.ALBUM, ItemListKey.ALBUM);

    const filteredAndSortedAlbums = useMemo(() => {
        const albums = albumsQuery.data?.items || [];
        const searched = searchLibraryItems(albums, debouncedSearchTerm, LibraryItem.ALBUM);
        return sortAlbumList(searched, sortBy, sortOrder);
    }, [albumsQuery.data?.items, debouncedSearchTerm, sortBy, sortOrder]);

    const controls = useDefaultItemListControls();

    const { releaseTypeEntries } = useArtistAlbumsGrouped(filteredAndSortedAlbums, routeId);

    const cq = useContainerQuery({
        '2xl': 1280,
        '3xl': 1440,
        lg: 960,
        md: 720,
        sm: 520,
        xl: 1152,
        xs: 360,
    });

    const binding = useSettingsStore((state) => state.hotkeys.bindings.localSearch);
    const searchInputRef = useRef<HTMLInputElement>(null);

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

    const itemsPerRow = getItemsPerRow(cq);

    const ReleaseTypeEntriesMemo = useMemo(() => {
        return releaseTypeEntries.map(({ albums, displayName, releaseType }) => (
            <AlbumSection
                albums={albums}
                controls={controls}
                enableExpansion
                itemsPerRow={itemsPerRow}
                key={releaseType}
                releaseType={releaseType}
                rows={rows}
                title={displayName}
            />
        ));
    }, [releaseTypeEntries, itemsPerRow, controls, rows]);

    return (
        <Grid.Col order={order} span={12}>
            <Stack gap="md">
                <Group gap="sm" w="100%">
                    <TextInput
                        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
                        }
                        styles={{
                            input: {
                                background: 'transparent',
                                border: '1px solid rgba(255, 255, 255, 0.05)',
                            },
                        }}
                        value={searchTerm}
                    />
                    <ListSortByDropdownControlled
                        filters={CLIENT_SIDE_ALBUM_FILTERS}
                        itemType={LibraryItem.ALBUM}
                        setSortBy={(value) =>
                            setAlbumArtistDetailSort(value as AlbumListSort, sortOrder)
                        }
                        sortBy={sortBy}
                    />
                    <ListSortOrderToggleButtonControlled
                        setSortOrder={(value) =>
                            setAlbumArtistDetailSort(sortBy, value as SortOrder)
                        }
                        sortOrder={sortOrder}
                    />
                    <GroupingTypeSelector />
                </Group>
                {releaseTypeEntries.length > 0 && (
                    <div className={styles.albumSectionContainer} ref={cq.ref}>
                        {cq.isCalculated && <>{ReleaseTypeEntriesMemo}</>}
                    </div>
                )}
            </Stack>
        </Grid.Col>
    );
};

function GroupingTypeSelector() {
    const { t } = useTranslation();
    const groupingType = useAppStore((state) => state.albumArtistDetailSort.groupingType);
    const setAlbumArtistDetailGroupingType = useAppStore(
        (state) => state.actions.setAlbumArtistDetailGroupingType,
    );

    return (
        <DropdownMenu>
            <DropdownMenu.Target>
                <ActionIcon icon="settings" variant="subtle" />
            </DropdownMenu.Target>
            <DropdownMenu.Dropdown>
                <DropdownMenu.Item
                    isSelected={groupingType === 'all'}
                    onClick={() => setAlbumArtistDetailGroupingType('all')}
                >
                    {t('page.albumArtistDetail.groupingTypeAll')}
                </DropdownMenu.Item>
                <DropdownMenu.Item
                    isSelected={groupingType === 'primary'}
                    onClick={() => setAlbumArtistDetailGroupingType('primary')}
                >
                    {t('page.albumArtistDetail.groupingTypePrimary')}
                </DropdownMenu.Item>
            </DropdownMenu.Dropdown>
        </DropdownMenu>
    );
}
