/**
 * Formulaire de saisie pour une simulation Expression Écrite.
 *
 * SEC-04 : validation Zod avant envoi (texte non vide, max 5 000 caractères).
 * SEC-05 : aucun dangerouslySetInnerHTML — le texte utilisateur est rendu comme texte.
 * Règle H : aucune logique métier — le composant reçoit tache, handlers et états par props.
 */

import { useEffect, useRef, useState, type FormEvent } from 'react'
import { Loader2 } from 'lucide-react'
import { z } from 'zod'
import { Button } from '@/shared/components/ui/button'
import { formatTache } from '@/entities/production/lib'
import type { SujetData, Tache } from '@/entities/production/types'
import type { ApiError } from '@/shared/types/api'
import { SujetDisplay } from './SujetDisplay'
import { SpecialCharsKeyboard } from './SpecialCharsKeyboard'

const textSchema = z.object({
  texte: z
    .string()
    .min(1, 'Le texte ne peut pas être vide.')
    .max(5000, 'Le texte ne doit pas dépasser 5 000 caractères.'),
})

function mapCorrectError(err: ApiError | null): string | null {
  if (!err) return null
  switch (err.code) {
    case 'SIMULATION_NOT_FOUND':
      return 'Simulation introuvable. Revenez en arrière et recommencez.'
    case 'AUTH_REQUIRED':
      return 'Votre session a expiré. Reconnectez-vous.'
    case 'VALIDATION_ERROR':
    case 'INVALID_BODY':
      return 'Le texte soumis est invalide. Vérifiez votre saisie.'
    default:
      return 'Correction impossible. Réessayez dans quelques instants.'
  }
}

interface Props {
  tache: Tache
  sujet: SujetData | null
  isSubmitting: boolean
  error: ApiError | null
  onSubmit: (texte: string) => void
  onBack: () => void
}

export function SimulationForm({ tache, sujet, isSubmitting, error, onSubmit, onBack }: Props) {
  const textareaRef = useRef<HTMLTextAreaElement>(null)
  const [texte, setTexte] = useState('')
  const [fieldError, setFieldError] = useState<string | null>(null)

  useEffect(() => {
    const el = textareaRef.current
    if (!el) return
    el.style.height = 'auto'
    el.style.height = `${el.scrollHeight}px`
  }, [texte])

  function handleInsert(char: string) {
    const el = textareaRef.current
    if (!el) {
      setTexte((prev) => prev + char)
      return
    }
    const start = el.selectionStart ?? texte.length
    const end = el.selectionEnd ?? texte.length
    const next = texte.slice(0, start) + char + texte.slice(end)
    setTexte(next)
    const caret = start + char.length
    requestAnimationFrame(() => {
      el.focus()
      el.setSelectionRange(caret, caret)
    })
  }

  function handleSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault()
    setFieldError(null)

    const parsed = textSchema.safeParse({ texte })
    if (!parsed.success) {
      setFieldError(parsed.error.flatten().fieldErrors.texte?.[0] ?? null)
      return
    }

    onSubmit(parsed.data.texte)
  }

  const apiError = mapCorrectError(error)
  const charCount = texte.length

  return (
    <div className="space-y-4">
      <div className="flex items-center gap-3">
        <button
          type="button"
          onClick={onBack}
          disabled={isSubmitting}
          className="text-sm text-ink-4 underline-offset-4 hover:text-ink-2 hover:underline disabled:pointer-events-none"
        >
          ← Retour
        </button>
        <h2 className="text-lg font-semibold text-ink-1">{formatTache(tache)}</h2>
      </div>

      <SujetDisplay sujet={sujet} />

      {apiError && (
        <div
          role="alert"
          className="rounded-md border border-danger/40 bg-danger-bg px-3 py-2 text-sm text-danger"
        >
          {apiError}
        </div>
      )}

      <form onSubmit={handleSubmit} className="space-y-3" noValidate>
        <div className="space-y-1.5">
          <label htmlFor="texte" className="text-sm font-medium text-ink-2">
            Votre production
          </label>
          <div className="sticky top-0 z-10 bg-canvas pb-1">
            <SpecialCharsKeyboard onInsert={handleInsert} disabled={isSubmitting} />
          </div>
          <textarea
            ref={textareaRef}
            id="texte"
            rows={8}
            value={texte}
            onChange={(e) => setTexte(e.target.value)}
            disabled={isSubmitting}
            placeholder="Rédigez votre texte ici…"
            aria-invalid={!!fieldError}
            aria-describedby={fieldError ? 'texte-error' : undefined}
            className="w-full resize-none overflow-y-hidden rounded-md border border-line bg-surface p-3 text-sm text-ink-1 placeholder:text-ink-5 focus:border-expria focus:outline-none focus:ring-2 focus:ring-expria/20 disabled:cursor-not-allowed disabled:opacity-50"
          />
          <div className="flex items-start justify-between gap-2">
            {fieldError ? (
              <p id="texte-error" className="text-sm text-danger">
                {fieldError}
              </p>
            ) : (
              <span />
            )}
            <span className={`text-xs tabular-nums ${charCount > 5000 ? 'text-danger' : 'text-ink-5'}`}>
              {charCount.toLocaleString('fr-FR')}&thinsp;/&thinsp;5 000
            </span>
          </div>
        </div>

        <Button type="submit" className="w-full" disabled={isSubmitting}>
          {isSubmitting ? (
            <>
              <Loader2 className="animate-spin" aria-hidden="true" />
              Correction en cours…
            </>
          ) : (
            'Envoyer pour correction'
          )}
        </Button>

        {isSubmitting && (
          <p className="text-center text-xs text-ink-4">
            La correction peut prendre jusqu'à 30 secondes.
          </p>
        )}
      </form>
    </div>
  )
}
