<template></template>

<script setup lang="ts">
import { onBeforeUnmount, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';
import AIDeskCoreInstance, {
    AI_DESK_EVENTS,
    SESSION_TYPE,
    StoreName,
    type ISessionModel,
} from '@tencentcloud/ai-desk-core';
import endedAudioUrl from '../assets/audio/ended.mp3';
import newMessageAudioUrl from '../assets/audio/newMessage.mp3';
import ringingAudioUrl from '../assets/audio/ringing.mp3';

const route = useRoute();

const RING_VOLUME = 0.5;
const ENDED_VOLUME = 0.2;

let ringingAudio: HTMLAudioElement | null = null;
let newMessageAudio: HTMLAudioElement | null = null;
let endedAudio: HTMLAudioElement | null = null;
let watchedStore: typeof AIDeskCoreInstance.coreStore | null = null;
let watchedEventCenter: typeof AIDeskCoreInstance.eventCenter | null = null;
const unlockedAudios = new WeakSet<HTMLAudioElement>();
let shouldRing = false;

const stopRingtone = () => {
    if (!ringingAudio) {
        return;
    }

    ringingAudio.pause();
    ringingAudio.currentTime = 0;
};

const startRingtone = () => {
    if (!ringingAudio || !ringingAudio.paused) {
        return;
    }

    const targetAudio = ringingAudio;
    void targetAudio.play()
        .then(() => {
            unlockedAudios.add(targetAudio);
        })
        .catch((error: unknown) => {
            if (error instanceof DOMException && error.name === 'AbortError') {
                return;
            }
            console.warn('待接听会话提示音播放失败：', error);
        });
};

const playOnce = (audio: HTMLAudioElement | null, name: string) => {
    if (!audio) {
        return;
    }

    audio.currentTime = 0;
    void audio.play()
        .then(() => {
            unlockedAudios.add(audio);
        })
        .catch((error: unknown) => {
            if (error instanceof DOMException && error.name === 'AbortError') {
                return;
            }
            console.warn(`${name}提示音播放失败：`, error);
        });
};

const onMessageReceived = () => {
    // playOnce(newMessageAudio, '新消息');
};

const onSessionEnded = () => {
    playOnce(endedAudio, '会话结束');
};

const syncRingtone = (list: ISessionModel<SESSION_TYPE.IM>[] = []) => {
    shouldRing = list.some(
        (session) => session.sessionData.sessionState === 'ringing',
    );

    if (shouldRing) {
        startRingtone();
    } else {
        stopRingtone();
    }
};

const detachListeners = () => {
    watchedStore?.unwatch(StoreName.SESSION, {
        IMSessionList: syncRingtone,
    });
    watchedEventCenter?.removeEvent(
        AI_DESK_EVENTS.MESSAGE_RECEIVED,
        onMessageReceived,
    );
    watchedEventCenter?.removeEvent(
        AI_DESK_EVENTS.SESSION_ENDED,
        onSessionEnded,
    );
    watchedStore = null;
    watchedEventCenter = null;
    shouldRing = false;
    stopRingtone();
};

const attachListeners = () => {
    if (route.path === '/login' || !AIDeskCoreInstance.isReady()) {
        detachListeners();
        return;
    }

    if (
        watchedStore === AIDeskCoreInstance.coreStore
        && watchedEventCenter === AIDeskCoreInstance.eventCenter
    ) {
        return;
    }

    detachListeners();
    watchedStore = AIDeskCoreInstance.coreStore;
    watchedEventCenter = AIDeskCoreInstance.eventCenter;
    watchedStore.watch(StoreName.SESSION, {
        IMSessionList: syncRingtone,
    });
    watchedEventCenter.addEvent(
        AI_DESK_EVENTS.MESSAGE_RECEIVED,
        onMessageReceived,
    );
    watchedEventCenter.addEvent(
        AI_DESK_EVENTS.SESSION_ENDED,
        onSessionEnded,
    );
};

const unlockAudioElement = (
    audio: HTMLAudioElement | null,
    keepPlaying = false,
) => {
    if (!audio || !audio.paused || unlockedAudios.has(audio)) {
        return;
    }

    const volume = audio.volume;
    audio.volume = keepPlaying ? volume : 0;
    void audio.play().then(() => {
        unlockedAudios.add(audio);
        if (!keepPlaying) {
            audio.pause();
            audio.currentTime = 0;
        }
        audio.volume = volume;
    }).catch(() => {
        audio.volume = volume;
    });
};

const unlockAudio = () => {
    if (shouldRing) {
        unlockAudioElement(ringingAudio, true);
    } else {
        unlockAudioElement(ringingAudio);
    }
    unlockAudioElement(newMessageAudio);
    unlockAudioElement(endedAudio);
};

const createAudio = (
    url: string,
    options: { loop?: boolean; volume?: number } = {},
) => {
    const audio = new Audio(url);
    audio.loop = options.loop ?? false;
    audio.volume = options.volume ?? 1;
    audio.preload = 'auto';
    return audio;
};

onMounted(() => {
    ringingAudio = createAudio(ringingAudioUrl, {
        loop: true,
        volume: RING_VOLUME,
    });
    newMessageAudio = createAudio(newMessageAudioUrl);
    endedAudio = createAudio(endedAudioUrl, { volume: ENDED_VOLUME });

    if (shouldRing) {
        startRingtone();
    }
    document.addEventListener('pointerdown', unlockAudio);
    document.addEventListener('keydown', unlockAudio);
});

watch(() => route.path, attachListeners, { immediate: true });

onBeforeUnmount(() => {
    document.removeEventListener('pointerdown', unlockAudio);
    document.removeEventListener('keydown', unlockAudio);
    detachListeners();

    [newMessageAudio, endedAudio].forEach((audio) => {
        audio?.pause();
        if (audio) {
            audio.currentTime = 0;
        }
    });
    ringingAudio = null;
    newMessageAudio = null;
    endedAudio = null;
});
</script>
