import { defineStore } from 'pinia';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';

import { sharedFeedFiltersDefaults } from '../../shared/constants';
import { useModalStore } from '../modal';
import { useVrStore } from '../vr';

import configRepository from '../../service/config';

export const useNotificationsSettingsStore = defineStore(
    'NotificationsSettings',
    () => {
        const vrStore = useVrStore();
        const modalStore = useModalStore();

        const { t } = useI18n();

        const overlayToast = ref('Game Running');
        const openVR = ref(false);
        const overlayNotifications = ref(true);
        const xsNotifications = ref(true);
        const ovrtHudNotifications = ref(true);
        const ovrtWristNotifications = ref(false);
        const imageNotifications = ref(true);
        const desktopToast = ref('Never');
        const afkDesktopToast = ref(false);
        const notificationTTS = ref('Never');
        const notificationTTSNickName = ref(false);
        const sharedFeedFilters = ref({
            noty: {
                Location: 'Off',
                OnPlayerJoined: 'VIP',
                OnPlayerLeft: 'VIP',
                OnPlayerJoining: 'VIP',
                Online: 'VIP',
                Offline: 'VIP',
                GPS: 'Off',
                Status: 'Off',
                invite: 'Friends',
                requestInvite: 'Friends',
                inviteResponse: 'Friends',
                requestInviteResponse: 'Friends',
                boop: 'Friends',
                friendRequest: 'On',
                Friend: 'On',
                Unfriend: 'On',
                DisplayName: 'VIP',
                TrustLevel: 'VIP',
                groupChange: 'On',
                'group.announcement': 'On',
                'group.informative': 'On',
                'group.invite': 'On',
                'group.joinRequest': 'Off',
                'group.transfer': 'On',
                'group.queueReady': 'On',
                'instance.closed': 'On',
                PortalSpawn: 'Everyone',
                Event: 'On',
                External: 'On',
                VideoPlay: 'Off',
                BlockedOnPlayerJoined: 'Off',
                BlockedOnPlayerLeft: 'Off',
                MutedOnPlayerJoined: 'Off',
                MutedOnPlayerLeft: 'Off',
                AvatarChange: 'Off',
                ChatBoxMessage: 'Off',
                Blocked: 'Off',
                Unblocked: 'Off',
                Muted: 'Off',
                Unmuted: 'Off'
            },
            wrist: {
                Location: 'On',
                OnPlayerJoined: 'Everyone',
                OnPlayerLeft: 'Everyone',
                OnPlayerJoining: 'Friends',
                Online: 'Friends',
                Offline: 'Friends',
                GPS: 'Friends',
                Status: 'Friends',
                invite: 'Friends',
                requestInvite: 'Friends',
                inviteResponse: 'Friends',
                requestInviteResponse: 'Friends',
                boop: 'Friends',
                friendRequest: 'On',
                Friend: 'On',
                Unfriend: 'On',
                DisplayName: 'Friends',
                TrustLevel: 'Friends',
                groupChange: 'On',
                'group.announcement': 'On',
                'group.informative': 'On',
                'group.invite': 'On',
                'group.joinRequest': 'On',
                'group.transfer': 'On',
                'group.queueReady': 'On',
                'instance.closed': 'On',
                PortalSpawn: 'Everyone',
                Event: 'On',
                External: 'On',
                VideoPlay: 'On',
                BlockedOnPlayerJoined: 'Off',
                BlockedOnPlayerLeft: 'Off',
                MutedOnPlayerJoined: 'Off',
                MutedOnPlayerLeft: 'Off',
                AvatarChange: 'Everyone',
                ChatBoxMessage: 'Off',
                Blocked: 'On',
                Unblocked: 'On',
                Muted: 'On',
                Unmuted: 'On'
            }
        });
        const isTestTTSVisible = ref(false);
        const notificationTTSVoice = ref(0);
        const TTSvoices = ref([]);
        const notificationTTSTest = ref('');
        const notificationPosition = ref('topCenter');
        const notificationTimeout = ref(3000);

        async function initNotificationsSettings() {
            const [
                overlayToastConfig,
                overlayNotificationsConfig,
                openVRConfig,
                xsNotificationsConfig,
                ovrtHudNotificationsConfig,
                ovrtWristNotificationsConfig,
                imageNotificationsConfig,
                desktopToastConfig,
                afkDesktopToastConfig,
                notificationTTSConfig,
                notificationTTSNickNameConfig,
                sharedFeedFiltersConfig,
                notificationTTSVoiceConfig,
                notificationPositionConfig,
                notificationTimeoutConfig
            ] = await Promise.all([
                configRepository.getString('VRCX_overlayToast', 'Game Running'),
                configRepository.getBool('VRCX_overlayNotifications', true),
                configRepository.getBool('openVR'),
                configRepository.getBool('VRCX_xsNotifications', true),
                configRepository.getBool('VRCX_ovrtHudNotifications', true),
                configRepository.getBool('VRCX_ovrtWristNotifications', false),
                configRepository.getBool('VRCX_imageNotifications', true),
                configRepository.getString('VRCX_desktopToast', 'Never'),
                configRepository.getBool('VRCX_afkDesktopToast', false),
                configRepository.getString('VRCX_notificationTTS', 'Never'),
                configRepository.getBool('VRCX_notificationTTSNickName', false),
                configRepository.getString(
                    'sharedFeedFilters',
                    JSON.stringify(sharedFeedFiltersDefaults)
                ),
                configRepository.getString('VRCX_notificationTTSVoice', '0'),
                configRepository.getString(
                    'VRCX_notificationPosition',
                    'topCenter'
                ),
                configRepository.getString('VRCX_notificationTimeout', '3000')
            ]);

            overlayToast.value = overlayToastConfig;
            openVR.value = openVRConfig;
            overlayNotifications.value = overlayNotificationsConfig;
            xsNotifications.value = xsNotificationsConfig;
            ovrtHudNotifications.value = ovrtHudNotificationsConfig;
            ovrtWristNotifications.value = ovrtWristNotificationsConfig;
            imageNotifications.value = imageNotificationsConfig;
            desktopToast.value = desktopToastConfig;
            afkDesktopToast.value = afkDesktopToastConfig;
            notificationTTS.value = notificationTTSConfig;
            notificationTTSNickName.value = notificationTTSNickNameConfig;
            sharedFeedFilters.value = JSON.parse(sharedFeedFiltersConfig);
            notificationTTSVoice.value = Number(notificationTTSVoiceConfig);
            TTSvoices.value = speechSynthesis.getVoices();
            notificationPosition.value = notificationPositionConfig;
            notificationTimeout.value = Number(notificationTimeoutConfig);

            initSharedFeedFilters();

            setTimeout(() => {
                // some workaround for failing to get voice list first run
                updateTTSVoices();
            }, 5000);
        }

        initNotificationsSettings();

        function setOverlayToast(value) {
            overlayToast.value = value;
            configRepository.setString('VRCX_overlayToast', value);
        }
        function setOverlayNotifications() {
            overlayNotifications.value = !overlayNotifications.value;
            configRepository.setBool(
                'VRCX_overlayNotifications',
                overlayNotifications.value
            );
        }
        function setOpenVR() {
            openVR.value = !openVR.value;
            configRepository.setBool('openVR', openVR.value);
        }
        function setXsNotifications() {
            xsNotifications.value = !xsNotifications.value;
            configRepository.setBool(
                'VRCX_xsNotifications',
                xsNotifications.value
            );
        }
        function setOvrtHudNotifications() {
            ovrtHudNotifications.value = !ovrtHudNotifications.value;
            configRepository.setBool(
                'VRCX_ovrtHudNotifications',
                ovrtHudNotifications.value
            );
        }
        function setOvrtWristNotifications() {
            ovrtWristNotifications.value = !ovrtWristNotifications.value;
            configRepository.setBool(
                'VRCX_ovrtWristNotifications',
                ovrtWristNotifications.value
            );
        }
        function setImageNotifications() {
            imageNotifications.value = !imageNotifications.value;
            configRepository.setBool(
                'VRCX_imageNotifications',
                imageNotifications.value
            );
        }

        function changeNotificationPosition(value) {
            notificationPosition.value = value;
            configRepository.setString(
                'VRCX_notificationPosition',
                notificationPosition.value
            );
            vrStore.updateVRConfigVars();
        }
        /**
         * @param {string} value
         */
        function setDesktopToast(value) {
            desktopToast.value = value;
            configRepository.setString('VRCX_desktopToast', value);
        }
        function setAfkDesktopToast() {
            afkDesktopToast.value = !afkDesktopToast.value;
            configRepository.setBool(
                'VRCX_afkDesktopToast',
                afkDesktopToast.value
            );
        }
        /**
         * @param {string} value
         */
        function setNotificationTTS(value) {
            notificationTTS.value = value;
            configRepository.setString('VRCX_notificationTTS', value);
        }
        function setNotificationTTSNickName() {
            notificationTTSNickName.value = !notificationTTSNickName.value;
            configRepository.setBool(
                'VRCX_notificationTTSNickName',
                notificationTTSNickName.value
            );
        }
        function initSharedFeedFilters() {
            if (!sharedFeedFilters.value.noty.Blocked) {
                sharedFeedFilters.value.noty.Blocked = 'Off';
                sharedFeedFilters.value.noty.Unblocked = 'Off';
                sharedFeedFilters.value.noty.Muted = 'Off';
                sharedFeedFilters.value.noty.Unmuted = 'Off';
                sharedFeedFilters.value.wrist.Blocked = 'On';
                sharedFeedFilters.value.wrist.Unblocked = 'On';
                sharedFeedFilters.value.wrist.Muted = 'On';
                sharedFeedFilters.value.wrist.Unmuted = 'On';
            }
            if (!sharedFeedFilters.value.noty['group.announcement']) {
                sharedFeedFilters.value.noty['group.announcement'] = 'On';
                sharedFeedFilters.value.noty['group.informative'] = 'On';
                sharedFeedFilters.value.noty['group.invite'] = 'On';
                sharedFeedFilters.value.noty['group.joinRequest'] = 'Off';
                sharedFeedFilters.value.wrist['group.announcement'] = 'On';
                sharedFeedFilters.value.wrist['group.informative'] = 'On';
                sharedFeedFilters.value.wrist['group.invite'] = 'On';
                sharedFeedFilters.value.wrist['group.joinRequest'] = 'On';
            }
            if (!sharedFeedFilters.value.noty['group.queueReady']) {
                sharedFeedFilters.value.noty['group.queueReady'] = 'On';
                sharedFeedFilters.value.wrist['group.queueReady'] = 'On';
            }
            if (!sharedFeedFilters.value.noty['instance.closed']) {
                sharedFeedFilters.value.noty['instance.closed'] = 'On';
                sharedFeedFilters.value.wrist['instance.closed'] = 'On';
            }
            if (!sharedFeedFilters.value.noty.External) {
                sharedFeedFilters.value.noty.External = 'On';
                sharedFeedFilters.value.wrist.External = 'On';
            }
            if (!sharedFeedFilters.value.noty.groupChange) {
                sharedFeedFilters.value.noty.groupChange = 'On';
                sharedFeedFilters.value.wrist.groupChange = 'On';
            }
            if (!sharedFeedFilters.value.noty['group.transfer']) {
                sharedFeedFilters.value.noty['group.transfer'] = 'On';
                sharedFeedFilters.value.wrist['group.transfer'] = 'On';
            }
            if (
                !sharedFeedFilters.value.noty.boop ||
                sharedFeedFilters.value.noty.boop === 'On'
            ) {
                sharedFeedFilters.value.noty.boop = 'Friends';
            }
            if (
                !sharedFeedFilters.value.wrist.boop ||
                sharedFeedFilters.value.wrist.boop === 'On'
            ) {
                sharedFeedFilters.value.wrist.boop = 'Friends';
            }
        }
        function setNotificationTTSVoice(index) {
            notificationTTSVoice.value = index;
            configRepository.setString(
                'VRCX_notificationTTSVoice',
                notificationTTSVoice.value.toString()
            );
        }

        function getTTSVoiceName() {
            let voices;
            if (WINDOWS) {
                voices = speechSynthesis.getVoices();
            } else {
                voices = TTSvoices.value;
            }
            if (voices.length === 0) {
                return '';
            }
            if (notificationTTSVoice.value >= voices.length) {
                setNotificationTTSVoice(0);
            }
            return voices[notificationTTSVoice.value].name;
        }

        async function changeTTSVoice(index) {
            setNotificationTTSVoice(index);
            let voices;
            if (WINDOWS) {
                voices = speechSynthesis.getVoices();
            } else {
                voices = TTSvoices.value;
            }
            if (voices.length === 0) {
                return;
            }
            const voiceName = voices[index].name;
            speechSynthesis.cancel();
            speak(voiceName);
        }

        function updateTTSVoices() {
            TTSvoices.value = speechSynthesis.getVoices();
            if (LINUX) {
                const voices = speechSynthesis.getVoices();
                let uniqueVoices = [];
                voices.forEach((voice) => {
                    if (!uniqueVoices.some((v) => v.lang === voice.lang)) {
                        uniqueVoices.push(voice);
                    }
                });
                uniqueVoices = uniqueVoices.filter((v) =>
                    v.lang.startsWith('en')
                );
                TTSvoices.value = uniqueVoices;
            }
        }
        async function saveNotificationTTS(value) {
            speechSynthesis.cancel();
            if (
                (await configRepository.getString('VRCX_notificationTTS')) ===
                    'Never' &&
                value !== 'Never'
            ) {
                speak('Notification text-to-speech enabled');
            }
            setNotificationTTS(value);
        }

        function testNotificationTTS() {
            speechSynthesis.cancel();
            speak(notificationTTSTest.value);
        }

        function speak(text) {
            const tts = new SpeechSynthesisUtterance();
            const voices = speechSynthesis.getVoices();
            if (voices.length === 0) {
                return;
            }
            let index = 0;
            if (notificationTTSVoice.value < voices.length) {
                index = notificationTTSVoice.value;
            }
            tts.voice = voices[index];
            tts.text = text;
            speechSynthesis.speak(tts);
        }

        function promptNotificationTimeout() {
            modalStore
                .prompt({
                    title: t('prompt.notification_timeout.header'),
                    description: t('prompt.notification_timeout.description'),
                    confirmText: t('prompt.notification_timeout.ok'),
                    cancelText: t('prompt.notification_timeout.cancel'),
                    inputValue: notificationTimeout.value / 1000,
                    pattern: /\d+$/,
                    errorMessage: t('prompt.notification_timeout.input_error')
                })
                .then(async ({ ok, value }) => {
                    if (!ok) return;
                    if (value && !isNaN(value)) {
                        notificationTimeout.value = Math.trunc(
                            Number(value) * 1000
                        );
                        await configRepository.setString(
                            'VRCX_notificationTimeout',
                            notificationTimeout.value.toString()
                        );
                        vrStore.updateVRConfigVars();
                    }
                })
                .catch(() => {});
        }

        return {
            overlayToast,
            openVR,
            overlayNotifications,
            xsNotifications,
            ovrtHudNotifications,
            ovrtWristNotifications,
            imageNotifications,
            desktopToast,
            afkDesktopToast,
            notificationTTS,
            notificationTTSNickName,
            sharedFeedFilters,
            isTestTTSVisible,
            notificationTTSVoice,
            TTSvoices,
            notificationTTSTest,
            notificationPosition,
            notificationTimeout,

            setOverlayToast,
            setOpenVR,
            setOverlayNotifications,
            setXsNotifications,
            setOvrtHudNotifications,
            setOvrtWristNotifications,
            setImageNotifications,
            setDesktopToast,
            setAfkDesktopToast,
            setNotificationTTS,
            setNotificationTTSNickName,
            getTTSVoiceName,
            changeTTSVoice,
            saveNotificationTTS,
            testNotificationTTS,
            speak,
            changeNotificationPosition,
            promptNotificationTimeout
        };
    }
);
