import { t } from 'i18next';
import isElectron from 'is-electron';
import { memo, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

import {
    SettingOption,
    SettingsSection,
} from '/@/renderer/features/settings/components/settings-section';
import { usePlaybackType, usePlayerStatus } from '/@/renderer/store';
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
import { Select } from '/@/shared/components/select/select';
import { Switch } from '/@/shared/components/switch/switch';
import { toast } from '/@/shared/components/toast/toast';
import { PlayerStatus, PlayerType } from '/@/shared/types/types';

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

const getAudioDevices = async () => {
    const devices = await navigator.mediaDevices.enumerateDevices();
    return (devices || []).filter((dev: MediaDeviceInfo) => dev.kind === 'audiooutput');
};

const getMpvAudioDevices = async () => {
    if (!mpvPlayer) {
        console.log('mpvPlayer not found');
        return [];
    }

    try {
        return await mpvPlayer.getAudioDevices();
    } catch (error) {
        console.error('Failed to get MPV audio devices:', error);
        return [];
    }
};

export const useAudioDevices = () => {
    const playbackType = usePlaybackType();
    const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]);

    useEffect(() => {
        const fetchAudioDevices = async () => {
            if (!isElectron()) {
                return;
            }

            if (playbackType === PlayerType.WEB) {
                getAudioDevices()
                    .then((dev) => {
                        const uniqueDevices = dev.filter(
                            (d, index, self) =>
                                index === self.findIndex((t) => t.deviceId === d.deviceId),
                        );
                        setAudioDevices(
                            uniqueDevices.map((d) => ({ label: d.label, value: d.deviceId })),
                        );
                    })
                    .catch(() =>
                        toast.error({
                            message: t('error.audioDeviceFetchError', {
                                postProcess: 'sentenceCase',
                            }),
                        }),
                    );
            } else if (playbackType === PlayerType.LOCAL && mpvPlayer) {
                try {
                    const devices = await getMpvAudioDevices();
                    const uniqueDevices = devices.filter(
                        (d, index, self) => index === self.findIndex((t) => t.value === d.value),
                    );
                    setAudioDevices(uniqueDevices);
                } catch {
                    toast.error({
                        message: t('error.audioDeviceFetchError', {
                            postProcess: 'sentenceCase',
                        }),
                    });
                }
            }
        };

        fetchAudioDevices();
    }, [playbackType]);

    return audioDevices;
};

export const AudioSettings = memo(() => {
    const { t } = useTranslation();
    const settings = usePlaybackSettings();
    const { setSettings } = useSettingsStoreActions();
    const status = usePlayerStatus();

    const audioDevices = useAudioDevices();

    const audioOptions: SettingOption[] = [
        {
            control: (
                <Select
                    data={[
                        {
                            disabled: !isElectron(),
                            label: 'MPV',
                            value: PlayerType.LOCAL,
                        },
                        { label: 'Web', value: PlayerType.WEB },
                    ]}
                    defaultValue={settings.type}
                    disabled={status === PlayerStatus.PLAYING}
                    onChange={(e) => {
                        setSettings({ playback: { type: e as PlayerType } });
                        ipc?.send('settings-set', { property: 'playbackType', value: e });
                    }}
                />
            ),
            description: t('setting.audioPlayer', {
                context: 'description',
                postProcess: 'sentenceCase',
            }),
            isHidden: !isElectron(),
            note:
                status === PlayerStatus.PLAYING
                    ? t('common.playerMustBePaused', { postProcess: 'sentenceCase' })
                    : undefined,
            title: t('setting.audioPlayer', { postProcess: 'sentenceCase' }),
        },
        {
            control: (
                <Select
                    clearable
                    data={audioDevices}
                    defaultValue={settings.audioDeviceId}
                    disabled={!isElectron()}
                    onChange={(e) => setSettings({ playback: { audioDeviceId: e } })}
                />
            ),
            description: t('setting.audioDevice', {
                context: 'description',
                postProcess: 'sentenceCase',
            }),
            title: t('setting.audioDevice', { postProcess: 'sentenceCase' }),
        },
        {
            control: (
                <Switch
                    defaultChecked={settings.webAudio}
                    onChange={(e) => {
                        setSettings({
                            playback: { webAudio: e.currentTarget.checked },
                        });
                    }}
                />
            ),
            description: t('setting.webAudio', {
                context: 'description',
                postProcess: 'sentenceCase',
            }),
            isHidden: settings.type !== PlayerType.WEB,
            note: t('common.restartRequired', { postProcess: 'sentenceCase' }),
            title: t('setting.webAudio', {
                postProcess: 'sentenceCase',
            }),
        },
        {
            control: (
                <Switch
                    defaultChecked={settings.preservePitch}
                    onChange={(e) => {
                        setSettings({
                            playback: { preservePitch: e.currentTarget.checked },
                        });
                    }}
                />
            ),
            description: t('setting.preservePitch', {
                context: 'description',
                postProcess: 'sentenceCase',
            }),
            isHidden: settings.type !== PlayerType.WEB,
            title: t('setting.preservePitch', {
                postProcess: 'sentenceCase',
            }),
        },
        {
            control: (
                <Switch
                    defaultChecked={settings.audioFadeOnStatusChange}
                    onChange={(e) => {
                        setSettings({
                            playback: {
                                audioFadeOnStatusChange: e.currentTarget.checked,
                            },
                        });
                    }}
                />
            ),
            description: t('setting.audioFadeOnStatusChange', {
                context: 'description',
                postProcess: 'sentenceCase',
            }),
            title: t('setting.audioFadeOnStatusChange', {
                postProcess: 'sentenceCase',
            }),
        },
    ];

    return (
        <SettingsSection
            options={audioOptions}
            title={t('page.setting.audio', { postProcess: 'sentenceCase' })}
        />
    );
});
