import { ref } from 'vue'
import type { AuditLogEntityTypes, AuditLogEntry, AuditLogFilters } from '~/shared/types'
import type { HydraCollection } from '~/shared/utils/api'
import { onAuthSessionCleared } from '~/shared/stores/auth'

/**
 * Cache module-level : evite un double-fetch si la page et le composant
 * Timeline demandent la meme page simultanement. Volontairement minimaliste :
 * on ne cache que le dernier resultat, pas un LRU par filtre — un CRM interne
 * n'en a pas besoin et le cache complexe complique le reset.
 *
 * Un logout / 401 doit purger ce cache : on s'enregistre au callback
 * `onAuthSessionCleared` expose par auth.ts.
 */
const lastCollection = ref<HydraCollection<AuditLogEntry> | null>(null)

function resetAuditLog(): void {
    lastCollection.value = null
}

// Auto-enregistrement singleton : si la session est invalidee (401,
// logout) le cache est purge automatiquement, evitant qu'un autre user
// connecte ensuite ne voit des donnees residuelles.
onAuthSessionCleared(resetAuditLog)

/**
 * Traduit le modele front (camelCase) en query params API Platform
 * (snake_case, avec la syntaxe performed_at[after] / [before]).
 *
 * @returns objet plat directement consommable par `useApi().get(url, query)`.
 */
function buildQuery(filters: AuditLogFilters | undefined): Record<string, string | number | string[]> {
    const query: Record<string, string | number | string[]> = {}
    if (!filters) return query

    // `entity_type` : chaine simple ou liste pour un filtre multi-selection.
    // Cote PHP, la syntaxe `entity_type[]=X&entity_type[]=Y` est requise pour
    // que $_GET['entity_type'] soit un tableau (sinon "last wins").
    if (Array.isArray(filters.entityType)) {
        if (filters.entityType.length > 0) query['entity_type[]'] = filters.entityType
    } else if (filters.entityType) {
        query.entity_type = filters.entityType
    }
    if (filters.entityId) query.entity_id = filters.entityId
    if (filters.action) query.action = filters.action
    if (filters.performedBy) query.performed_by = filters.performedBy
    if (filters.performedAtAfter) query['performed_at[after]'] = filters.performedAtAfter
    if (filters.performedAtBefore) query['performed_at[before]'] = filters.performedAtBefore
    if (filters.page) query.page = filters.page
    if (filters.itemsPerPage) query.itemsPerPage = filters.itemsPerPage

    return query
}

/**
 * Composable partage entre la page globale d'audit (admin) et le composant
 * Timeline. Expose des methodes de lecture + une fonction `resetAuditLog()`
 * pour purger le cache (conforme a la regle CLAUDE.md sur les composables
 * singletons, cf. `useSidebar.resetSidebar`).
 */
// Accept explicitement JSON-LD : API Platform 4 retourne un tableau PLAT (liste
// d'items, sans envelope de pagination) sous `application/json`, et un objet
// Hydra complet avec `member`, `totalItems` et `view` (first/last/next/previous)
// sous `application/ld+json`. Pour obtenir `view` cote front — indispensable
// a la pagination prev/next — on force donc ld+json.
const JSONLD_HEADERS = { Accept: 'application/ld+json' } as const

export function useAuditLog() {
    const api = useApi()

    async function fetchLogs(filters?: AuditLogFilters): Promise<HydraCollection<AuditLogEntry>> {
        return api.get<HydraCollection<AuditLogEntry>>(
            '/audit-logs',
            buildQuery(filters),
            { toast: false, headers: JSONLD_HEADERS },
        )
    }

    /**
     * Variante de `fetchLogs` qui met a jour le cache `lastCollection`.
     * N'est utilisee que par la page admin — le composant Timeline appelle
     * `fetchEntityLogs` qui bypass le cache pour ne pas polluer la reference
     * page-level quand plusieurs timelines sont ouvertes.
     */
    async function fetchLogsCached(filters?: AuditLogFilters): Promise<HydraCollection<AuditLogEntry>> {
        const data = await fetchLogs(filters)
        lastCollection.value = data
        return data
    }

    async function fetchLogById(id: string): Promise<AuditLogEntry> {
        return api.get<AuditLogEntry>(`/audit-logs/${id}`, {}, { toast: false, headers: JSONLD_HEADERS })
    }

    /**
     * Liste des valeurs distinctes de `entity_type` pour alimenter le filtre
     * multi-selection. Alimente par un endpoint DBAL, aucune cache cote front
     * (la liste peut evoluer a chaque nouvelle ecriture d'audit).
     */
    async function fetchEntityTypes(): Promise<string[]> {
        const data = await api.get<AuditLogEntityTypes>(
            '/audit-log-entity-types',
            {},
            { toast: false, headers: JSONLD_HEADERS },
        )
        return data.entityTypes ?? []
    }

    async function fetchEntityLogs(
        entityType: string,
        entityId: string | number,
        page: number = 1,
        itemsPerPage: number = 10,
    ): Promise<HydraCollection<AuditLogEntry>> {
        // Volontairement via `fetchLogs` (sans cache) pour ne pas ecraser
        // `lastCollection` — la timeline peut etre rendue simultanement a
        // la page globale et doit rester independante.
        //
        // Le backend pagine a 30 par defaut (paginationItemsPerPage) ; on
        // passe explicitement itemsPerPage ici pour que la taille de page
        // soit alignee avec l'UX timeline (10 items + bouton "Voir plus").
        // Sans ce param, le client slice a 10 et rate 20 entrees par page.
        return fetchLogs({
            entityType,
            entityId: String(entityId),
            page,
            itemsPerPage,
        })
    }

    // API publique : on expose volontairement deux noms distincts pour les
    // deux contrats (cache/no-cache). Aliaser `fetchLogs` vers la version
    // cachee trompait les appelants : un consommateur qui destructurait
    // `{ fetchLogs }` en pensant faire un appel neutre polluait en realite
    // `lastCollection`, effet indetectable sans lire l'impl.
    return {
        lastCollection,
        fetchLogsCached,
        fetchLogById,
        fetchEntityLogs,
        fetchEntityTypes,
        resetAuditLog,
    }
}
