'use client' import { createContext, useContext, useState, useEffect, useRef, useCallback } from 'react' import { useSession } from 'next-auth/react' import { getLocalStorageAiConsent, setLocalStorageAiConsent, removeLocalStorageAiConsent } from '@/lib/consent/ai-consent-client' import { updateAISettings } from '@/app/actions/ai-settings' import { AiConsentModal } from './ai-consent-modal' import { toast } from 'sonner' import { useLanguage } from '@/lib/i18n' interface AiConsentContextType { hasAiConsent: boolean requestAiConsent: () => Promise revokeConsent: () => Promise } const AiConsentContext = createContext(undefined) interface AiConsentProviderProps { children: React.ReactNode initialPersistentConsent?: boolean } export function AiConsentProvider({ children, initialPersistentConsent = false }: AiConsentProviderProps) { const { data: session, update: updateSession } = useSession() const { t } = useLanguage() const [persistentConsent, setPersistentConsent] = useState(false) const [sessionConsent, setSessionConsent] = useState(false) const [modalOpen, setModalOpen] = useState(false) const [hydrated, setHydrated] = useState(false) const pendingResolveRef = useRef<((value: boolean) => void) | null>(null) useEffect(() => { const local = getLocalStorageAiConsent() if (local || initialPersistentConsent) { setPersistentConsent(true) if (initialPersistentConsent && !local) { setLocalStorageAiConsent(true) } } setHydrated(true) }, [initialPersistentConsent]) useEffect(() => { if (session?.aiSessionConsent === true) { setSessionConsent(true) } else if (session?.aiSessionConsent === false) { setSessionConsent(false) } }, [session?.aiSessionConsent]) const hasAiConsent = hydrated && (persistentConsent || sessionConsent || session?.aiSessionConsent === true) const requestAiConsent = useCallback((): Promise => { if (hasAiConsent) { return Promise.resolve(true) } setModalOpen(true) return new Promise((resolve) => { pendingResolveRef.current = resolve }) }, [hasAiConsent]) const handleConfirm = async (remember: boolean) => { setModalOpen(false) const grantConsentLocally = async () => { if (remember) { setLocalStorageAiConsent(true) setPersistentConsent(true) await updateAISettings({ aiProcessingConsent: true }) } else { await updateSession({ aiSessionConsent: true }) setSessionConsent(true) } } try { const res = await fetch('/api/user/ai-consent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ consent: true, remember }), }) if (res.ok) { const data = await res.json().catch(() => ({})) if (data?.auditLogged === false) { console.warn('[AiConsentProvider] Consent saved without audit trail') } if (remember) { setLocalStorageAiConsent(true) setPersistentConsent(true) try { await updateAISettings({ aiProcessingConsent: true }) } catch (e) { console.error('[AiConsentProvider] Failed to sync consent to DB:', e) } } else { await updateSession({ aiSessionConsent: true }) setSessionConsent(true) } } else { try { await grantConsentLocally() } catch (fallbackError) { console.error('[AiConsentProvider] Consent fallback failed:', fallbackError) toast.error(t('consent.ai.auditFailed') || 'Impossible d’enregistrer votre consentement. Réessayez.') pendingResolveRef.current?.(false) pendingResolveRef.current = null return } } pendingResolveRef.current?.(true) pendingResolveRef.current = null } catch (e) { console.error('[AiConsentProvider] Failed to log consent audit:', e) try { await grantConsentLocally() pendingResolveRef.current?.(true) } catch (fallbackError) { console.error('[AiConsentProvider] Consent fallback failed:', fallbackError) toast.error(t('consent.ai.auditFailed') || 'Impossible d’enregistrer votre consentement. Réessayez.') pendingResolveRef.current?.(false) } pendingResolveRef.current = null } } const handleClose = () => { setModalOpen(false) toast.warning(t('consent.ai.aborted') || 'Traitement IA annulé (consentement refusé).') pendingResolveRef.current?.(false) pendingResolveRef.current = null } const revokeConsent = async () => { removeLocalStorageAiConsent() setPersistentConsent(false) setSessionConsent(false) try { await fetch('/api/user/ai-consent', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ consent: false, remember: true }), }) } catch (e) { console.error('[AiConsentProvider] Failed to log revocation:', e) } try { await updateSession({ aiSessionConsent: false }) } catch (e) { console.error('[AiConsentProvider] Failed to clear session consent:', e) } if (session?.user) { try { await updateAISettings({ aiProcessingConsent: false }) } catch (e) { console.error('[AiConsentProvider] Failed to sync revocation to DB:', e) } } toast.success(t('consent.ai.revokedToast') || 'Consentement IA révoqué avec succès.') } return ( {children} ) } export function useAiConsent() { const context = useContext(AiConsentContext) if (context === undefined) { throw new Error('useAiConsent must be used within an AiConsentProvider') } return context }