// plugins/notificationSocket.client.ts
// Connects to the /notification realtime service (native WebSocket, no
// third-party client) once authenticated, and feeds incoming notifications
// into the notification store + toast — replaces the old 30s poll.
// @ts-ignore
import {defineNuxtPlugin, useRuntimeConfig, useNuxtApp} from '#app'
import {watch} from 'vue'
import {useAuthStore} from '~/stores/auth'
import {useNotificationsStore} from '~/stores/notification'

const RECONNECT_BASE_DELAY_MS = 1000
const RECONNECT_MAX_DELAY_MS = 30000

export default defineNuxtPlugin(() => {
    const config = useRuntimeConfig()
    const auth = useAuthStore()
    const notifications = useNotificationsStore()

    let socket: WebSocket | null = null
    let reconnectAttempts = 0
    let reconnectTimer: ReturnType<typeof setTimeout> | null = null
    let closedByUs = false

    function handleMessage(event: MessageEvent) {
        let payload: any
        try {
            payload = JSON.parse(event.data)
        } catch {
            return
        }

        if (payload?.type !== 'notification') return

        // The service's worker spreads notification.data into the top-level
        // message alongside type/title/body (see notification/src/queue/notificationWorker.js),
        // so id/created_at arrive flat, not nested under a "data" key.
        notifications.receiveRealtime({
            id: payload.id,
            subject: payload.title,
            message: payload.body,
            created_at: payload.created_at
        })

        const {$notification} = useNuxtApp()
        // @ts-ignore
        $notification.call(payload.body)
    }

    function scheduleReconnect() {
        if (closedByUs) return

        const delay = Math.min(RECONNECT_BASE_DELAY_MS * (2 ** reconnectAttempts), RECONNECT_MAX_DELAY_MS)
        reconnectAttempts++

        reconnectTimer = setTimeout(connect, delay)
    }

    async function connect() {
        // @ts-ignore
        if (!auth.authenticated || !auth.user?.id) return

        const {$api} = useNuxtApp()
        let token: string | null = null

        try {
            // @ts-ignore
            const response = await $api.post('/user/notification/socket-token', {})
            token = response.data?.data?.token || null
        } catch {
            scheduleReconnect()
            return
        }

        if (!token) {
            scheduleReconnect()
            return
        }

        // @ts-ignore
        const wsUrl = config.public.notificationWsUrl
        socket = new WebSocket(`${wsUrl}?token=${encodeURIComponent(token)}`)

        socket.onopen = () => {
            reconnectAttempts = 0
        }

        socket.onmessage = handleMessage

        socket.onclose = () => {
            socket = null
            scheduleReconnect()
        }

        socket.onerror = () => {
            socket?.close()
        }
    }

    function disconnect() {
        closedByUs = true
        if (reconnectTimer) clearTimeout(reconnectTimer)
        socket?.close()
        socket = null
    }

    // @ts-ignore
    if (auth.authenticated && auth.user?.id) {
        closedByUs = false
        connect()
    }

    // @ts-ignore
    watch(() => auth.authenticated, (isAuthed: boolean) => {
        if (isAuthed) {
            closedByUs = false
            reconnectAttempts = 0
            connect()
        } else {
            disconnect()
        }
    })

    // @ts-ignore
    watch(() => auth.user?.id, (userId: number | undefined) => {
        if (userId && !socket) {
            closedByUs = false
            connect()
        }
    })
})
