import { defineStore } from 'pinia'
import type { UserData } from '~/shared/types/user-data'
import type { Site } from '~/shared/types/sites'
import { getCurrentUser, login, logout } from '~/shared/services/auth'

/**
 * Callbacks enregistres par les composables singletons qui doivent
 * reinitialiser leur etat quand la session est invalidee (ex: expiration
 * JWT, logout depuis un intercepteur 401). Utilise le pattern
 * "callback registration" (Option C) pour eviter une dependance croisee
 * depuis shared/ vers modules/ — chaque composable s'auto-enregistre.
 */
const onSessionClearedCallbacks: Array<() => void> = []

/**
 * Enregistre un callback a invoquer lorsque clearSession() est appelee.
 * Typiquement invoque au setup-time du composable (module-level), donc
 * une seule fois par instance de composable singleton.
 */
export function onAuthSessionCleared(cb: () => void): void {
    onSessionClearedCallbacks.push(cb)
}

export const useAuthStore = defineStore('auth', {
    state: () => ({
        user: null as UserData | null,
        isLoading: false,
        checked: false
    }),
    getters: {
        isAuthenticated: (state) => Boolean(state.user)
    },
    actions: {
        clearSession() {
            this.user = null
            this.checked = true
            this.isLoading = false
            // Notifie les composables singletons (useCurrentSite, etc.) afin
            // qu'ils reinitialisation leur etat — necessaire quand la session
            // est invalidee par un intercepteur 401 sans passer par logout.vue.
            onSessionClearedCallbacks.forEach((cb) => cb())
        },
        async ensureSession() {
            if (this.checked) {
                return this.user
            }

            this.checked = true

            try {
                const me = await getCurrentUser()
                this.user = me
                return me
            } catch {
                this.user = null
                return null
            }
        },
        async login(username: string, password: string) {
            this.isLoading = true

            try {
                await login(username, password)
                const me = await getCurrentUser()
                this.user = me
                this.checked = true
                return me
            } finally {
                this.isLoading = false
            }
        },
        async logout() {
            this.isLoading = true

            try {
                await logout()
            } catch {
                // Ignore logout errors so we can still clear local auth state.
            } finally {
                this.user = null
                this.checked = true
                this.isLoading = false
            }
        },
        async refreshUser() {
            try {
                const me = await getCurrentUser()
                this.user = me
            } catch {
                // Silently fail — user session might have expired
            }
        },
        /**
         * Action dediee au switch du site courant (ticket 3 module Sites).
         * Utilisee par useCurrentSite apres la confirmation serveur, et en
         * rollback si la requete PATCH echoue apres une mutation optimistic.
         * Passer explicitement par une action plutot que muter user.currentSite
         * directement garantit la tracabilite Pinia (devtools).
         */
        setCurrentSite(site: Site | null) {
            if (this.user) {
                this.user.currentSite = site
            }
        }
    }
})
