import isElectron from 'is-electron';
import { useEffect, useRef } from 'react';

import { getItemImageUrl } from '/@/renderer/components/item-image/item-image';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
import { useSetRating } from '/@/renderer/features/shared/hooks/use-set-rating';
import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
import { usePlayerActions, usePlayerStore, useRemoteSettings } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { toast } from '/@/shared/components/toast/toast';
import { LibraryItem } from '/@/shared/types/domain-types';
import { PlayerShuffle } from '/@/shared/types/types';

const remote = isElectron() ? window.api.remote : null;
const ipc = isElectron() ? window.api.ipc : null;

export const useRemote = () => {
    const { mediaSkipForward, setVolume } = usePlayerActions();
    const player = usePlayerStore();

    const remoteSettings = useRemoteSettings();
    const setRating = useSetRating();
    const addToFavoritesMutation = useCreateFavorite({});
    const removeFromFavoritesMutation = useDeleteFavorite({});

    const isRemoteEnabled = remoteSettings.enabled;

    // Initialize the remote
    useEffect(() => {
        if (!isRemoteEnabled) {
            return;
        }

        logFn.debug(logMsg[LogCategory.REMOTE].initializingRemoteSettings, {
            category: LogCategory.REMOTE,
            meta: {
                enabled: remoteSettings.enabled,
                port: remoteSettings.port,
                username: remoteSettings.username,
            },
        });

        remote
            ?.updateSetting(
                remoteSettings.enabled,
                remoteSettings.port,
                remoteSettings.username,
                remoteSettings.password,
            )
            .catch((error) => {
                logFn.error(logMsg[LogCategory.REMOTE].failedToEnableRemote, {
                    category: LogCategory.REMOTE,
                    meta: { error },
                });
                toast.warn({ message: error, title: 'Failed to enable remote' });
            });
        // We only want to fire this once
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    useEffect(() => {
        if (!isRemoteEnabled || !remote) {
            return;
        }

        remote.requestPosition((_e: unknown, data: { position: number }) => {
            logFn.debug(logMsg[LogCategory.REMOTE].requestPositionReceived, {
                category: LogCategory.REMOTE,
                meta: { position: data.position },
            });
            const newTime = data.position;
            player.mediaSeekToTimestamp(newTime);
        });

        remote.requestSeek((_e: unknown, data: { offset: number }) => {
            logFn.debug(logMsg[LogCategory.REMOTE].requestSeekReceived, {
                category: LogCategory.REMOTE,
                meta: { offset: data.offset },
            });
            mediaSkipForward(data.offset);
        });

        remote.requestRating(
            (_e: unknown, data: { id: string; rating: number; serverId: string }) => {
                logFn.debug(logMsg[LogCategory.REMOTE].requestRatingReceived, {
                    category: LogCategory.REMOTE,
                    meta: { id: data.id, rating: data.rating, serverId: data.serverId },
                });
                setRating(data.serverId, [data.id], LibraryItem.SONG, data.rating);
            },
        );

        remote.requestVolume((_e: unknown, data: { volume: number }) => {
            logFn.debug(logMsg[LogCategory.REMOTE].requestVolumeReceived, {
                category: LogCategory.REMOTE,
                meta: { volume: data.volume },
            });
            setVolume(data.volume);
        });

        remote.requestFavorite(
            (_e: unknown, data: { favorite: boolean; id: string; serverId: string }) => {
                logFn.debug(logMsg[LogCategory.REMOTE].requestFavoriteReceived, {
                    category: LogCategory.REMOTE,
                    meta: { favorite: data.favorite, id: data.id, serverId: data.serverId },
                });
                const mutator = data.favorite
                    ? addToFavoritesMutation
                    : removeFromFavoritesMutation;
                mutator.mutate({
                    apiClientProps: { serverId: data.serverId },
                    query: {
                        id: [data.id],
                        type: LibraryItem.SONG,
                    },
                });
            },
        );

        return () => {
            ipc?.removeAllListeners('request-position');
            ipc?.removeAllListeners('request-seek');
            ipc?.removeAllListeners('request-volume');
            ipc?.removeAllListeners('request-favorite');
            ipc?.removeAllListeners('request-rating');
        };
    }, [
        addToFavoritesMutation,
        isRemoteEnabled,
        mediaSkipForward,
        player,
        removeFromFavoritesMutation,
        setVolume,
        setRating,
    ]);

    // Send initial song if one is already playing
    const isInitializedRef = useRef(false);
    useEffect(() => {
        if (isInitializedRef.current || !isRemoteEnabled || !remote) {
            return;
        }

        isInitializedRef.current = true;

        const currentSong = player.getCurrentSong();

        if (currentSong) {
            logFn.debug(logMsg[LogCategory.REMOTE].sendingInitialSong, {
                category: LogCategory.REMOTE,
                meta: {
                    artistName: currentSong.artistName,
                    id: currentSong.id,
                    name: currentSong.name,
                },
            });

            const imageUrl =
                getItemImageUrl({
                    id: currentSong.id,
                    imageUrl: currentSong.imageUrl,
                    itemType: LibraryItem.SONG,
                    serverId: currentSong._serverId,
                    type: 'itemCard',
                    useRemoteUrl: true,
                }) || null;

            remote.updateSong(currentSong, imageUrl);
        }
    }, [isRemoteEnabled, player]);

    usePlayerEvents(
        {
            onCurrentSongChange: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                logFn.debug(logMsg[LogCategory.REMOTE].updateSongSent, {
                    category: LogCategory.REMOTE,
                    meta: {
                        artistName: properties.song?.artistName,
                        id: properties.song?.id,
                        index: properties.index,
                        name: properties.song?.name,
                    },
                });
                if (properties.song) {
                    const song = properties.song;
                    const imageUrl =
                        getItemImageUrl({
                            id: song.id,
                            imageUrl: song.imageUrl,
                            itemType: LibraryItem.SONG,
                            serverId: song._serverId,
                            type: 'itemCard',
                            useRemoteUrl: true,
                        }) || null;

                    remote.updateSong(song, imageUrl);
                } else {
                    remote.updateSong(undefined);
                }
            },
            onPlayerProgress: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                logFn.debug(logMsg[LogCategory.REMOTE].updatePositionSent, {
                    category: LogCategory.REMOTE,
                    meta: { timestamp: properties.timestamp },
                });
                remote.updatePosition(properties.timestamp);
            },
            onPlayerRepeat: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                logFn.debug(logMsg[LogCategory.REMOTE].updateRepeatSent, {
                    category: LogCategory.REMOTE,
                    meta: { repeat: properties.repeat },
                });
                remote.updateRepeat(properties.repeat);
            },
            onPlayerShuffle: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                const isShuffleEnabled = properties.shuffle !== PlayerShuffle.NONE;
                logFn.debug(logMsg[LogCategory.REMOTE].updateShuffleSent, {
                    category: LogCategory.REMOTE,
                    meta: { isShuffleEnabled, shuffle: properties.shuffle },
                });
                remote.updateShuffle(isShuffleEnabled);
            },
            onPlayerStatus: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                logFn.debug(logMsg[LogCategory.REMOTE].updatePlaybackSent, {
                    category: LogCategory.REMOTE,
                    meta: { status: properties.status },
                });
                remote.updatePlayback(properties.status);
            },
            onPlayerVolume: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                logFn.debug(logMsg[LogCategory.REMOTE].updateVolumeSent, {
                    category: LogCategory.REMOTE,
                    meta: { volume: properties.volume },
                });
                remote.updateVolume(properties.volume);
            },
            onUserFavorite: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                logFn.debug(logMsg[LogCategory.REMOTE].updateFavoriteSent, {
                    category: LogCategory.REMOTE,
                    meta: {
                        favorite: properties.favorite,
                        id: properties.id,
                        serverId: properties.serverId,
                    },
                });
                remote.updateFavorite(properties.favorite, properties.serverId, properties.id);
            },
            onUserRating: (properties) => {
                if (!isRemoteEnabled || !remote) {
                    return;
                }

                logFn.debug(logMsg[LogCategory.REMOTE].updateRatingSent, {
                    category: LogCategory.REMOTE,
                    meta: {
                        id: properties.id,
                        rating: properties.rating || 0,
                        serverId: properties.serverId,
                    },
                });
                remote.updateRating(properties.rating || 0, properties.serverId, properties.id);
            },
        },
        [],
    );
};

export const RemoteHook = () => {
    useRemote();
    return null;
};
