import { AnimatePresence, motion } from 'motion/react';
import { Variants } from 'motion/react';
import {
    CSSProperties,
    memo,
    MouseEvent,
    ReactNode,
    useCallback,
    useEffect,
    useRef,
    useState,
} from 'react';
import { useTranslation } from 'react-i18next';

import styles from './mobile-fullscreen-player.module.css';

import { useItemImageUrl } from '/@/renderer/components/item-image/item-image';
import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller';
import { Lyrics } from '/@/renderer/features/lyrics/lyrics';
import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue';
import { MobileFullscreenPlayerAlbumArt } from '/@/renderer/features/player/components/mobile-fullscreen-player-album-art';
import { MobileFullscreenPlayerBottomControls } from '/@/renderer/features/player/components/mobile-fullscreen-player-bottom-controls';
import { MobileFullscreenPlayerControls } from '/@/renderer/features/player/components/mobile-fullscreen-player-controls';
import { MobileFullscreenPlayerHeader } from '/@/renderer/features/player/components/mobile-fullscreen-player-header';
import { MobileFullscreenPlayerMetadata } from '/@/renderer/features/player/components/mobile-fullscreen-player-metadata';
import { MobileFullscreenPlayerProgress } from '/@/renderer/features/player/components/mobile-fullscreen-player-progress';
import {
    useIsRadioActive,
    useRadioPlayer,
} from '/@/renderer/features/radio/hooks/use-radio-player';
import { useSetFavorite } from '/@/renderer/features/shared/hooks/use-set-favorite';
import { useSetRating } from '/@/renderer/features/shared/hooks/use-set-rating';
import { useFastAverageColor } from '/@/renderer/hooks';
import {
    useCurrentServer,
    useFullScreenPlayerStore,
    useFullScreenPlayerStoreActions,
    useGeneralSettings,
    usePlayerData,
    usePlayerSong,
    useSetFullScreenPlayerStore,
} from '/@/renderer/store';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Text } from '/@/shared/components/text/text';
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';

const mainBackground = 'var(--theme-colors-background)';

const backgroundImageVariants: Variants = {
    closed: {
        opacity: 0,
        transition: {
            duration: 0.8,
            ease: 'linear',
        },
    },
    initial: {
        opacity: 0,
    },
    open: (custom) => {
        const { isOpen } = custom;
        return {
            opacity: isOpen ? 1 : 0,
            transition: {
                duration: 0.4,
                ease: 'linear',
            },
        };
    },
};

interface BackgroundImageProps {
    dynamicBackground: boolean | undefined;
    dynamicIsImage: boolean | undefined;
}

const BackgroundImage = memo(({ dynamicBackground, dynamicIsImage }: BackgroundImageProps) => {
    const currentSong = usePlayerSong();
    const { nextSong } = usePlayerData();

    const currentImageUrl = useItemImageUrl({
        id: currentSong?.imageId || undefined,
        itemType: LibraryItem.SONG,
        type: 'itemCard',
    });

    const nextImageUrl = useItemImageUrl({
        id: nextSong?.imageId || undefined,
        itemType: LibraryItem.SONG,
        type: 'itemCard',
    });

    const [imageState, setImageState] = useState({
        bottomImage: nextImageUrl,
        current: 0,
        topImage: currentImageUrl,
    });

    const previousSongRef = useRef<string | undefined>(currentSong?._uniqueId);
    const imageStateRef = useRef(imageState);

    useEffect(() => {
        imageStateRef.current = imageState;
    }, [imageState]);

    // Update images when song changes
    useEffect(() => {
        if (currentSong?._uniqueId === previousSongRef.current) {
            return;
        }

        const isTop = imageStateRef.current.current === 0;

        setImageState({
            bottomImage: isTop ? currentImageUrl : nextImageUrl,
            current: isTop ? 1 : 0,
            topImage: isTop ? nextImageUrl : currentImageUrl,
        });

        previousSongRef.current = currentSong?._uniqueId;
    }, [currentSong?._uniqueId, currentImageUrl, nextSong?._uniqueId, nextImageUrl]);

    if (!dynamicBackground || !dynamicIsImage) {
        return null;
    }

    const getBackgroundImageUrl = (
        imageUrl: string | undefined,
        songId: string | undefined,
        albumId: string | undefined,
    ) => {
        if (!imageUrl || !songId || !albumId) {
            return imageUrl;
        }
        return imageUrl.replace(songId, albumId);
    };

    // Determine which song IDs to use for keys and image URLs
    const topSongId = imageState.current === 0 ? currentSong?._uniqueId : nextSong?._uniqueId;
    const bottomSongId = imageState.current === 0 ? nextSong?._uniqueId : currentSong?._uniqueId;
    const topSong = imageState.current === 0 ? currentSong : nextSong;
    const bottomSong = imageState.current === 0 ? nextSong : currentSong;

    return (
        <AnimatePresence initial={false} mode="sync">
            {imageState.current === 0 && imageState.topImage && (
                <motion.div
                    animate="open"
                    className={styles.backgroundImage}
                    custom={{ isOpen: imageState.current === 0 }}
                    exit="closed"
                    initial="open"
                    key={`top-${topSongId || 'none'}`}
                    style={
                        {
                            backgroundImage: imageState.topImage
                                ? `url("${getBackgroundImageUrl(
                                      imageState.topImage,
                                      topSong?.id,
                                      topSong?.albumId,
                                  )}"), url("${imageState.topImage}")`
                                : undefined,
                        } as CSSProperties
                    }
                    variants={backgroundImageVariants}
                />
            )}

            {imageState.current === 1 && imageState.bottomImage && (
                <motion.div
                    animate="open"
                    className={styles.backgroundImage}
                    custom={{ isOpen: imageState.current === 1 }}
                    exit="closed"
                    initial="open"
                    key={`bottom-${bottomSongId || 'none'}`}
                    style={
                        {
                            backgroundImage: imageState.bottomImage
                                ? `url("${getBackgroundImageUrl(
                                      imageState.bottomImage,
                                      bottomSong?.id,
                                      bottomSong?.albumId,
                                  )}"), url("${imageState.bottomImage}")`
                                : undefined,
                        } as CSSProperties
                    }
                    variants={backgroundImageVariants}
                />
            )}
        </AnimatePresence>
    );
});

BackgroundImage.displayName = 'BackgroundImage';

const overlayVariants: Variants = {
    closed: {
        opacity: 0,
        transition: {
            duration: 0,
        },
    },
    initial: {
        opacity: 1,
    },
    open: {
        opacity: 1,
        transition: {
            duration: 0,
        },
    },
};

interface BackgroundImageOverlayProps {
    dynamicBackground: boolean | undefined;
    dynamicImageBlur: number | undefined;
}

const BackgroundImageOverlay = memo(
    ({ dynamicBackground, dynamicImageBlur }: BackgroundImageOverlayProps) => {
        const currentSong = usePlayerSong();
        const { nextSong } = usePlayerData();

        const [overlayState, setOverlayState] = useState({
            bottomSongId: nextSong?._uniqueId,
            current: 0,
            topSongId: currentSong?._uniqueId,
        });

        const previousSongRef = useRef<string | undefined>(currentSong?._uniqueId);
        const overlayStateRef = useRef(overlayState);

        useEffect(() => {
            overlayStateRef.current = overlayState;
        }, [overlayState]);

        // Update overlays when song changes
        useEffect(() => {
            if (currentSong?._uniqueId === previousSongRef.current) {
                return;
            }

            const isTop = overlayStateRef.current.current === 0;

            setOverlayState({
                bottomSongId: isTop ? currentSong?._uniqueId : nextSong?._uniqueId,
                current: isTop ? 1 : 0,
                topSongId: isTop ? nextSong?._uniqueId : currentSong?._uniqueId,
            });

            previousSongRef.current = currentSong?._uniqueId;
        }, [currentSong?._uniqueId, nextSong?._uniqueId]);

        if (!dynamicBackground) {
            return null;
        }

        return (
            <AnimatePresence initial={false} mode="sync">
                {overlayState.current === 0 && (
                    <motion.div
                        animate="open"
                        className={styles.backgroundImageOverlay}
                        exit="closed"
                        initial="open"
                        key={`top-${overlayState.topSongId || 'none'}`}
                        style={
                            {
                                '--image-blur': `${dynamicImageBlur ?? 0}rem`,
                            } as CSSProperties
                        }
                        variants={overlayVariants}
                    />
                )}

                {overlayState.current === 1 && (
                    <motion.div
                        animate="open"
                        className={styles.backgroundImageOverlay}
                        exit="closed"
                        initial="open"
                        key={`bottom-${overlayState.bottomSongId || 'none'}`}
                        style={
                            {
                                '--image-blur': `${dynamicImageBlur ?? 0}rem`,
                            } as CSSProperties
                        }
                        variants={overlayVariants}
                    />
                )}
            </AnimatePresence>
        );
    },
);

BackgroundImageOverlay.displayName = 'BackgroundImageOverlay';

interface MobilePlayerContainerProps {
    children: ReactNode;
    dynamicBackground: boolean | undefined;
    dynamicIsImage: boolean | undefined;
}

const MobilePlayerContainer = memo(
    ({ children, dynamicBackground, dynamicIsImage }: MobilePlayerContainerProps) => {
        const currentSong = usePlayerSong();
        const imageUrl = useItemImageUrl({
            id: currentSong?.imageId || undefined,
            imageUrl: currentSong?.imageUrl,
            itemType: LibraryItem.SONG,
            type: 'itemCard',
        });
        const { background } = useFastAverageColor({
            algorithm: 'dominant',
            src: imageUrl,
            srcLoaded: true,
        });

        let backgroundColor = mainBackground;
        if (dynamicBackground) {
            if (dynamicIsImage && background) {
                const rgbMatch = background.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
                if (rgbMatch) {
                    backgroundColor = `rgba(${rgbMatch[1]}, ${rgbMatch[2]}, ${rgbMatch[3]}, 0.3)`;
                } else {
                    backgroundColor = background;
                }
            } else {
                backgroundColor = background || mainBackground;
            }
        }

        return (
            <motion.div
                animate="open"
                className={styles.container}
                exit="closed"
                initial="closed"
                style={{
                    backgroundColor,
                }}
                variants={mobileContainerVariants}
            >
                <BackgroundImage
                    dynamicBackground={dynamicBackground}
                    dynamicIsImage={dynamicIsImage}
                />
                {children}
            </motion.div>
        );
    },
);

MobilePlayerContainer.displayName = 'MobilePlayerContainer';

const mobileContainerVariants: Variants = {
    closed: {
        transition: {
            duration: 0.5,
            ease: 'easeInOut',
        },
        y: '100%',
    },
    open: {
        transition: {
            duration: 0.5,
            ease: 'easeInOut',
        },
        y: 0,
    },
};

export const MobileFullscreenPlayer = () => {
    const { t } = useTranslation();
    const setFullScreenPlayerStore = useSetFullScreenPlayerStore();
    const { setStore } = useFullScreenPlayerStoreActions();
    const { activeTab, dynamicBackground, dynamicImageBlur, dynamicIsImage } =
        useFullScreenPlayerStore();
    const currentSong = usePlayerSong();
    const { currentSong: currentSongData } = usePlayerData();
    const isRadioActive = useIsRadioActive();
    const { isPlaying: isRadioPlaying, metadata: radioMetadata, stationName } = useRadioPlayer();
    const server = useCurrentServer();

    const isPlayingRadio = isRadioActive && isRadioPlaying;
    const effectiveDynamicBackground = dynamicBackground && !isPlayingRadio;
    const setFavorite = useSetFavorite();
    const { showRatings: showRatingsSetting } = useGeneralSettings();
    const setRating = useSetRating();

    const [isPageHovered, setIsPageHovered] = useState(false);

    const handleToggleFullScreenPlayer = useCallback(() => {
        setFullScreenPlayerStore({ expanded: false });
    }, [setFullScreenPlayerStore]);

    const handleToggleContextMenu = useCallback(
        (e: MouseEvent<HTMLButtonElement | HTMLDivElement>) => {
            e.preventDefault();
            e.stopPropagation();

            if (!currentSong) {
                return;
            }

            ContextMenuController.call({
                cmd: { items: [currentSong], type: LibraryItem.SONG },
                event: e as unknown as MouseEvent<HTMLDivElement>,
            });
        },
        [currentSong],
    );

    const handleToggleQueue = useCallback(() => {
        setStore({ activeTab: activeTab === 'queue' ? 'player' : 'queue' });
    }, [activeTab, setStore]);

    const handleToggleFavorite = useCallback(
        (e: MouseEvent<HTMLButtonElement>) => {
            e.stopPropagation();
            const song = currentSongData;
            if (!song?.id) return;

            setFavorite(song._serverId, [song.id], LibraryItem.SONG, !song.userFavorite);
        },
        [currentSongData, setFavorite],
    );

    const handleToggleLyrics = useCallback(() => {
        setStore({ activeTab: activeTab === 'lyrics' ? 'player' : 'lyrics' });
    }, [activeTab, setStore]);

    const handleUpdateRating = useCallback(
        (rating: number) => {
            if (!currentSong?.id) return;

            setRating(currentSong._serverId, [currentSong.id], LibraryItem.SONG, rating);
        },
        [currentSong, setRating],
    );

    const isPlayerState = activeTab !== 'queue' && activeTab !== 'lyrics';
    const isQueueState = activeTab === 'queue';
    const isLyricsState = activeTab === 'lyrics';
    const isSongDefined = Boolean(currentSong?.id);
    const showRating =
        showRatingsSetting &&
        isSongDefined &&
        (server?.type === ServerType.NAVIDROME || server?.type === ServerType.SUBSONIC);

    return (
        <MobilePlayerContainer
            dynamicBackground={effectiveDynamicBackground}
            dynamicIsImage={dynamicIsImage}
        >
            <BackgroundImageOverlay
                dynamicBackground={effectiveDynamicBackground}
                dynamicImageBlur={dynamicImageBlur}
            />
            <motion.div
                animate={{
                    opacity: isPlayerState ? 1 : 0,
                    zIndex: isPlayerState ? 2 : 1,
                }}
                className={styles.playerState}
                onMouseEnter={() => setIsPageHovered(true)}
                onMouseLeave={() => setIsPageHovered(false)}
                transition={{ duration: 0.3, ease: 'easeInOut' }}
            >
                <MobileFullscreenPlayerHeader
                    currentSong={currentSong}
                    isPageHovered={isPageHovered}
                    onClose={handleToggleFullScreenPlayer}
                />
                <MobileFullscreenPlayerAlbumArt />
                <MobileFullscreenPlayerMetadata
                    currentSong={currentSong}
                    onToggleFavorite={handleToggleFavorite}
                    onUpdateRating={handleUpdateRating}
                    radioArtist={isPlayingRadio ? (radioMetadata?.artist ?? undefined) : undefined}
                    radioStationName={isPlayingRadio ? (stationName ?? undefined) : undefined}
                    radioTitle={isPlayingRadio ? (radioMetadata?.title ?? undefined) : undefined}
                    showRating={showRating}
                />
                <MobileFullscreenPlayerProgress currentSong={currentSong} />
                <MobileFullscreenPlayerControls currentSong={currentSong} />
                <MobileFullscreenPlayerBottomControls
                    isLyricsActive={isLyricsState}
                    isQueueActive={isQueueState}
                    onToggleContextMenu={handleToggleContextMenu}
                    onToggleLyrics={handleToggleLyrics}
                    onToggleQueue={handleToggleQueue}
                />
            </motion.div>

            <AnimatePresence>
                {isQueueState && (
                    <motion.div
                        animate={{ opacity: 1 }}
                        className={styles.queueState}
                        exit={{ opacity: 0 }}
                        initial={{ opacity: 0 }}
                        style={{ zIndex: 2 }}
                        transition={{ duration: 0.3, ease: 'easeInOut' }}
                    >
                        <div className={styles.queueHeader}>
                            <ActionIcon
                                icon="arrowDownS"
                                onClick={handleToggleFullScreenPlayer}
                                size="sm"
                                variant={isPageHovered ? 'default' : 'subtle'}
                            />
                            <ActionIcon
                                icon="x"
                                iconProps={{ size: 'xl' }}
                                onClick={handleToggleQueue}
                                size="sm"
                                variant={isPageHovered ? 'default' : 'subtle'}
                            />
                        </div>
                        <div className={styles.queueContent}>
                            <PlayQueue listKey={ItemListKey.FULL_SCREEN} searchTerm={undefined} />
                        </div>
                    </motion.div>
                )}
            </AnimatePresence>

            <AnimatePresence>
                {isLyricsState && (
                    <motion.div
                        animate={{ opacity: 1 }}
                        className={styles.lyricsState}
                        exit={{ opacity: 0 }}
                        initial={{ opacity: 0 }}
                        style={{ zIndex: 2 }}
                        transition={{ duration: 0.3, ease: 'easeInOut' }}
                    >
                        <div className={styles.lyricsHeader}>
                            <ActionIcon
                                icon="arrowDownS"
                                onClick={handleToggleFullScreenPlayer}
                                size="sm"
                                variant={isPageHovered ? 'default' : 'subtle'}
                            />
                            <Text fw={600} size="lg">
                                {t('page.fullscreenPlayer.lyrics')}
                            </Text>
                            <ActionIcon
                                icon="x"
                                iconProps={{ size: 'xl' }}
                                onClick={handleToggleLyrics}
                                size="sm"
                                variant={isPageHovered ? 'default' : 'subtle'}
                            />
                        </div>
                        <div className={styles.lyricsContent}>
                            <Lyrics fadeOutNoLyricsMessage={false} />
                        </div>
                    </motion.div>
                )}
            </AnimatePresence>
        </MobilePlayerContainer>
    );
};
