/**
 * Composable de gestion du site courant (ticket 3 module Sites).
 *
 * Pattern aligne sur `useSidebar` : state singleton au niveau module,
 * hydrate depuis `useAuthStore().user`, mute de maniere optimistic avec
 * rollback si la requete PATCH `/api/me/current-site` echoue.
 *
 * Garantie d'unicite : le flag `switching` bloque les double-clicks
 * concurrents. Le reset explicite est appele au logout
 * (voir `modules/core/pages/logout.vue`).
 *
 * Auto-select : aucun. Le backend (`UserRbacProcessor::ensureCurrentSiteConsistency`)
 * garantit deja l'invariant "user avec sites non vide => currentSite non null"
 * apres tout PATCH /rbac. Le front consomme l'etat renvoye tel quel.
 *
 * Contrainte d'appel : `useCurrentSite()` doit etre invoque au top du
 * `setup()` d'un composant (ou d'un autre composable appele au setup).
 * Les dependances `useI18n`, `useApi` et `useAuthStore` sont resolues
 * a l'initialisation et reutilisees par `switchSite` — ceci evite le
 * "Must be called at the top of a setup function" qui se produirait
 * si on les appelait paresseusement depuis une fonction async declenchee
 * par un handler d'event (hors contexte setup).
 */
import { ref } from 'vue'
import type { Site } from '~/shared/types/sites'
import { onAuthSessionCleared } from '~/shared/stores/auth'

const currentSite = ref<Site | null>(null)
const availableSites = ref<Site[]>([])
const switching = ref(false)

// Enregistrement unique au niveau module (singleton) : quand clearSession()
// est appelee par l'intercepteur 401 de useApi, le state local est purgé
// de la meme facon qu'au logout explicite (logout.vue).
onAuthSessionCleared(() => {
    currentSite.value = null
    availableSites.value = []
    switching.value = false
})

export function useCurrentSite() {
    // Resolution au setup : les 3 services doivent etre invoques dans un
    // contexte composant. Leur capture ici permet a switchSite() de
    // s'executer plus tard (handler de click, async) sans crash.
    const auth = useAuthStore()
    const api = useApi()
    const { t } = useI18n()
    const { loadSidebar } = useSidebar()

    /**
     * Synchronise le state singleton depuis le store auth. A appeler au
     * mount du SiteSelector (ou via un watcher sur `auth.user`).
     */
    function syncFromAuth(): void {
        availableSites.value = auth.user?.sites ?? []
        currentSite.value = auth.user?.currentSite ?? null
    }

    /**
     * Bascule le site courant. Optimistic UI : la mutation locale precede
     * la requete HTTP. En cas d'echec (`api.patch` throw), l'etat local est
     * restaure — le store auth n'a PAS ete muté a ce stade (la propagation
     * `auth.setCurrentSite` se fait uniquement apres un succes HTTP), donc
     * aucun rollback cote auth n'est necessaire.
     *
     * Garde anti-double-submit : si un switch est deja en vol, le second
     * appel est un no-op silencieux.
     */
    async function switchSite(site: Site): Promise<void> {
        if (switching.value) {
            return
        }

        const previousLocal = currentSite.value
        currentSite.value = site
        switching.value = true

        try {
            await api.patch(
                '/me/current-site',
                { site: `/api/sites/${site.id}` },
                { toastSuccessMessage: t('sites.selector.switchSuccess') },
            )
            // Propage au store auth via l'action dediee — plus tracable que
            // la mutation directe et garantit la notification des watchers.
            // N'est appele qu'apres un succes HTTP donc pas de rollback a
            // prevoir sur cette ligne.
            auth.setCurrentSite(site)

            // Apres un switch reussi : recharger la sidebar (les filtres de
            // modules peuvent dependre du site courant via SiteScopedQueryExtension)
            // et invalider toutes les donnees de page pour eviter que l'utilisateur
            // voie les donnees de l'ancien site sous un toast "Site change".
            try {
                await loadSidebar()
            } catch {
                // No-op : la sidebar non rafraichie n'est pas bloquante.
            }
            try {
                await refreshNuxtData()
            } catch {
                // No-op : certaines pages n'ont pas de useAsyncData a invalider.
            }
        } catch (error) {
            currentSite.value = previousLocal
            throw error
        } finally {
            switching.value = false
        }
    }

    /**
     * Vide l'etat singleton. Appele au logout pour eviter qu'un user
     * suivant (connecte sur le meme onglet) voie les sites de l'ancien.
     */
    function resetCurrentSite(): void {
        currentSite.value = null
        availableSites.value = []
        switching.value = false
    }

    return {
        currentSite,
        availableSites,
        switching,
        switchSite,
        syncFromAuth,
        resetCurrentSite,
    }
}
