/**
 * Provider de flux simulation — partage l'état entre /simulation/ee et /sujets.
 *
 * Hérite de la state machine de useSimulation mais déplace la source de vérité
 * hors du hook pour qu'elle survive aux navigations React Router (Option A — cf.
 * plan de refonte UX "page /sujets avec cartes").
 *
 * Règle H : aucune logique métier — les mutations s'appuient sur entities/.
 */

import { useEffect, useRef, useState, type ReactNode } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
import { useMutation } from '@tanstack/react-query'
import {
  createSimulation,
  getSimulationState,
  updateSujet as updateSujetApi,
} from '@/entities/production/api'
import { correctEe } from '@/entities/report/api'
import type { CreateSimulationPayload, Production, Tache } from '@/entities/production/types'
import type { Report } from '@/entities/report/types'
import type { ApiError } from '@/shared/types/api'
import type { SujetData } from '@/entities/production/types'
import { SimulationFlowContext, type FlowValue, type SimulationStep } from './simulationFlow'

const TACHES_SANS_CATALOGUE: Tache[] = ['EO_T1']
const LS_SIMULATION_ID_KEY = 'expria_simulation_id'

export function SimulationFlowProvider({ children }: { children: ReactNode }) {
  const [step, setStep] = useState<SimulationStep>('idle')
  const [production, setProduction] = useState<Production | null>(null)
  const navigate = useNavigate()
  const location = useLocation()
  const hydratedRef = useRef(false)

  // FTD-21 — restauration de session depuis localStorage au montage.
  // Si `rapport === null` → simulation en cours, on restaure le state et redirige
  // vers /simulation/ee. Sinon (rapport présent ou erreur/404) → on nettoie.
  useEffect(() => {
    if (hydratedRef.current) return
    hydratedRef.current = true

    const id = localStorage.getItem(LS_SIMULATION_ID_KEY)
    if (!id) return

    getSimulationState(id)
      .then((state) => {
        if (state.rapport !== null) {
          localStorage.removeItem(LS_SIMULATION_ID_KEY)
          return
        }
        setProduction({
          id: state.simulation_id,
          tache: state.tache,
          mode: state.mode,
          created_at: state.created_at,
          sujet: state.sujet,
          contenu: state.contenu ?? undefined,
          sujet_id: state.sujet?.id,
        })
        setStep('task-selected')
        if (!location.pathname.startsWith('/simulation/ee')) {
          navigate('/simulation/ee')
        }
      })
      .catch(() => {
        localStorage.removeItem(LS_SIMULATION_ID_KEY)
      })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const createMutation = useMutation({
    mutationFn: createSimulation,
    onSuccess: (data) => {
      setProduction(data)
      const hasCatalogue = !TACHES_SANS_CATALOGUE.includes(data.tache)
      setStep(hasCatalogue ? 'choosing-subject' : 'task-selected')
      // Navigation initiale vers /sujets pour les tâches avec catalogue —
      // gérée ici (et non dans un useEffect sticky côté SimulationPage) pour
      // éviter la boucle infinie quand l'utilisateur revient depuis /sujets.
      if (hasCatalogue) {
        navigate('/sujets')
      }
    },
  })

  const correctMutation = useMutation({
    mutationFn: correctEe,
    onMutate: () => setStep('correcting'),
    onSuccess: (_data, variables) => {
      setStep('done')
      localStorage.removeItem(LS_SIMULATION_ID_KEY)
      // Navigation vers le rapport déclenchée ici (plutôt que depuis un
      // useEffect sticky côté SimulationPage) — une seule fois par correction,
      // pas de redirection en boucle si l'utilisateur revient sur /simulation/ee.
      navigate(`/rapport/${variables.simulationId}`)
    },
    onError: () => setStep('task-selected'),
  })

  function selectTask(payload: CreateSimulationPayload): void {
    createMutation.mutate(payload)
  }

  function submitText(texte: string, nclcCible: 9 | 10 = 9): void {
    if (!production) return
    correctMutation.mutate({
      simulationId: production.id,
      contenu: texte,
      tache: production.tache,
      nclc_cible: nclcCible,
    })
  }

  function changeSubject(sujet: SujetData): void {
    // FTD-21 — persiste le changement côté backend (best-effort : l'UI ne bloque pas).
    if (production) {
      void updateSujetApi(production.id, sujet.id).catch(() => {
        // silencieux : le sujet reste localement, le resume ramènera l'ancien si échec
      })
    }
    setProduction((p) => (p ? { ...p, sujet } : p))
  }

  function reset(): void {
    setStep('idle')
    setProduction(null)
    localStorage.removeItem(LS_SIMULATION_ID_KEY)
    createMutation.reset()
    correctMutation.reset()
  }

  const value: FlowValue = {
    step,
    production,
    sujet: production?.sujet ?? null,
    report: (correctMutation.data ?? null) as Report | null,
    isCreating: createMutation.isPending,
    isCorrecting: correctMutation.isPending,
    createError: createMutation.error as ApiError | null,
    correctError: correctMutation.error as ApiError | null,
    selectTask,
    submitText,
    changeSubject,
    setStep,
    reset,
  }

  return <SimulationFlowContext.Provider value={value}>{children}</SimulationFlowContext.Provider>
}
