'use client'
import { useEffect, useLayoutEffect, useRef, useState, useTransition } from 'react'
import type { BrandConfig, Survey } from '@/lib/types'
import type { AnswerValue, FormAnswers, FormSchema, Screen } from '@/lib/form-engine.types'
import {
  answerKey,
  applyAnswer,
  expandInstances,
  initialState,
  isRequiredAndUnanswered,
  next,
  back,
  resolveScreens,
} from '@/lib/form-engine'
import { loadDraft, saveDraft, clearDraft } from '@/lib/storage'
import { submitSurvey } from '@/app/actions/submit-survey'
import { ConsentScreen } from './consent-screen'
import { ProgressBar } from './progress-bar'
import { QuestionRenderer } from './question-renderer'

type Stage = 'consent' | 'form' | 'success' | 'error'

interface WizardFormProps {
  survey: Survey
  schema: FormSchema
}

function isEmpty(v: AnswerValue): boolean {
  return v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0)
}

function valueFor(screen: Screen, answers: FormAnswers): AnswerValue {
  if (!screen.question) return null
  const v = answers[answerKey(screen.question.code, screen.instanceId ?? undefined)]
  return v === undefined ? null : v
}

/** Resume en la primera pantalla sin responder (o la sección que la precede). */
function resumeScreenId(schema: FormSchema, answers: FormAnswers): string {
  const screens = resolveScreens(schema, answers)
  const firstUnanswered = screens.findIndex(
    (s) => s.kind === 'question' && isEmpty(valueFor(s, answers))
  )
  if (firstUnanswered <= 0) return screens[0]?.id ?? 'end'
  const prev = screens[firstUnanswered - 1]
  return prev.kind === 'section' ? prev.id : screens[firstUnanswered].id
}

export function WizardForm({ survey, schema }: WizardFormProps) {
  const [stage, setStage] = useState<Stage>('consent')
  const [consentOperativo, setConsentOperativo] = useState(false)
  const [consentMacroN1, setConsentMacroN1] = useState(false)
  const [state, setState] = useState(() => initialState(schema))
  const [errors, setErrors] = useState<Record<string, string>>({})
  const [hydrated, setHydrated] = useState(false)
  const [a11yAnnounce, setA11yAnnounce] = useState('')
  const answerAreaRef = useRef<HTMLDivElement>(null)
  const [hasOverflow, setHasOverflow] = useState(false)
  const [submitError, setSubmitError] = useState<string | null>(null)
  const [isPending, startTransition] = useTransition()

  useEffect(() => {
    const draft = loadDraft(survey.id)
    if (Object.keys(draft).length > 0) {
      setState({ answers: draft, currentScreenId: resumeScreenId(schema, draft) })
    }
    setHydrated(true)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [survey.id])

  useEffect(() => {
    if (!hydrated) return
    saveDraft(survey.id, state.answers)
  }, [state.answers, hydrated, survey.id])

  const screens = resolveScreens(schema, state.answers)
  const idx = screens.findIndex((s) => s.id === state.currentScreenId)
  const screen = screens[idx] ?? screens[0]

  useEffect(() => {
    if (!screen) return
    if (screen.kind === 'section') setA11yAnnounce(`Sección: ${screen.question?.prompt}`)
    else if (screen.kind === 'question') setA11yAnnounce(`Pregunta ${screen.question?.code}: ${screen.question?.prompt}`)
    else setA11yAnnounce('Fin del formulario')
  }, [screen?.id])

  // El fade de wizard-answer-area solo debe aparecer si hay overflow real —
  // CSS no puede expresar esa condición (no hay selector para "este elemento
  // scrollea"), así que se mide el DOM. Se remide al cambiar de pantalla
  // (cambia todo el contenido) y al resize (puede cambiar cuántas opciones entran).
  useLayoutEffect(() => {
    const el = answerAreaRef.current
    setHasOverflow(el ? el.scrollHeight > el.clientHeight : false)
  }, [screen?.id])

  useEffect(() => {
    function recalc() {
      const el = answerAreaRef.current
      setHasOverflow(el ? el.scrollHeight > el.clientHeight : false)
    }
    window.addEventListener('resize', recalc)
    return () => window.removeEventListener('resize', recalc)
  }, [])

  if (stage === 'consent') {
    return (
      <ConsentScreen
        brandConfig={survey.brand_config}
        onAccept={(op, macro) => {
          setConsentOperativo(op)
          setConsentMacroN1(macro)
          setStage('form')
        }}
      />
    )
  }

  if (stage === 'success') {
    return (
      <div className="survey-wrapper">
        <div className="thank-you-container" role="main">
          <h1 className="thank-you-title">¡Gracias por participar!</h1>
          <p className="thank-you-body">
            Tu respuesta fue registrada correctamente. Recordá que la encuesta es anónima: no hay
            forma de vincular tus respuestas con tu identidad.
          </p>
          <p className="thank-you-body">
            Los resultados agregados ayudarán a {survey.brand_config?.org_name ?? 'tu empresa'} a
            diseñar mejores apoyos para las personas cuidadoras.
          </p>
        </div>
      </div>
    )
  }

  if (stage === 'error') {
    return (
      <div className="survey-wrapper">
        <div className="error-container" role="main">
          <h1 className="error-title">No se pudo enviar la encuesta</h1>
          <p>Hubo un error al guardar tus respuestas. Podés intentarlo de nuevo.</p>
          {submitError && <pre className="no-survey-hint">{submitError}</pre>}
          <button
            type="button"
            className="btn btn-primary"
            onClick={() => { setSubmitError(null); setStage('form') }}
          >
            Volver e intentar de nuevo
          </button>
        </div>
      </div>
    )
  }

  if (!screen) return null

  const currentValue = valueFor(screen, state.answers)
  const questionScreens = screens.filter((s) => s.kind !== 'end')
  const ordinal = Math.min(idx + 1, questionScreens.length)
  const sectionScreens = screens.filter((s) => s.kind === 'section')
  const sectionOrdinal = screen.kind === 'section' ? sectionScreens.findIndex((s) => s.id === screen.id) + 1 : null

  // Contexto de instancia ("Familiar X de N") — derivado, no decide visibilidad ni navegación.
  let instanceCtx: { label: string; ordinal: number; total: number } | null = null
  if (screen.instanceId && screen.question?.instance_of) {
    const generator = schema.questions.find((q) => q.code === screen.question!.instance_of)
    if (generator) {
      const instances = expandInstances(generator, state.answers)
      const ord = instances.findIndex((i) => i.instanceId === screen.instanceId)
      if (ord >= 0) {
        instanceCtx = { label: instances[ord].optionValue, ordinal: ord + 1, total: instances.length }
      }
    }
  }

  function handleChange(value: AnswerValue) {
    if (!screen.question) return
    const code = screen.question.code
    const instanceId = screen.instanceId ?? undefined

    setState((prev) => applyAnswer(prev, schema, code, value, instanceId))

    setErrors((prev) => {
      if (!prev[code]) return prev
      const { [code]: _, ...rest } = prev
      return rest
    })
  }

  function handleNext() {
    if (isRequiredAndUnanswered(screen, state.answers)) {
      setErrors((e) => ({ ...e, [screen.question!.code]: 'Este campo es obligatorio.' }))
      return
    }
    setState((s) => next(s, schema))
  }

  function handleBack() {
    setState((s) => back(s, schema))
  }

  function handleSubmit() {
    if (isPending) return
    // state.answers usa claves "code:instanceId" — se descompone una sola vez
    // acá, al borde cliente/servidor; el validador (lib/submit-validation.ts)
    // recibe la forma explícita {code, instanceId, value}[].
    const answers = Object.entries(state.answers).map(([key, value]) => {
      const sep = key.indexOf(':')
      return { code: key.slice(0, sep), instanceId: key.slice(sep + 1), value }
    })

    startTransition(async () => {
      try {
        const result = await submitSurvey({
          surveyId: survey.id,
          answers,
          consentOperativo,
          consentMacroN1,
        })
        if (result.success) {
          clearDraft(survey.id)
          setStage('success')
        } else {
          setSubmitError(result.error)
          setStage('error')
        }
      } catch {
        // Falla de red al invocar el Server Action (fetch failed) — no es un
        // error que submitSurvey pueda devolver como result, hay que capturarlo acá.
        setSubmitError('No pudimos enviar tu respuesta. Verificá tu conexión e intentá de nuevo.')
        setStage('error')
      }
    })
  }

  const bc: BrandConfig | null = survey.brand_config

  return (
    <div className="wizard-shell">
      <div aria-live="polite" aria-atomic="true" className="sr-only" role="status">
        {a11yAnnounce}
      </div>

      <div className="wizard-topbar">
        {bc?.org_name && (
          <p className="brand-text wizard-topbar-brand">
            Encuesta de <strong>{bc.org_name}</strong>
          </p>
        )}
        <ProgressBar answered={ordinal} total={questionScreens.length} />
      </div>

      <main className="wizard-stage" id="wizard-stage">
        {screen.kind === 'section' && screen.question && (
          <div className="wizard-section-screen" role="region" aria-labelledby="wizard-section-title">
            <p className="wizard-section-number">
              Sección {sectionOrdinal} de {sectionScreens.length}
            </p>
            <h2 id="wizard-section-title" className="wizard-section-title">
              {screen.question.prompt}
            </h2>
            {screen.question.hint && <p className="wizard-section-desc">{screen.question.hint}</p>}
          </div>
        )}

        {screen.kind === 'question' && screen.question && (
          <>
            <div className="wizard-prompt-block">
              {instanceCtx && (
                <span className="wizard-instance-badge">
                  {instanceCtx.label} · familiar {instanceCtx.ordinal} de {instanceCtx.total}
                </span>
              )}
              <span className="wizard-prompt-code">{screen.question.code}</span>
              <h2 className="wizard-prompt-text">{screen.question.prompt}</h2>
              {screen.question.hint && <p className="wizard-prompt-hint">{screen.question.hint}</p>}
            </div>
            <div
              ref={answerAreaRef}
              className={`wizard-answer-area${hasOverflow ? ' has-overflow' : ''}`}
            >
              <QuestionRenderer
                question={screen.question}
                value={currentValue}
                onChange={handleChange}
                error={errors[screen.question.code]}
                answers={state.answers}
              />
            </div>
          </>
        )}

        {screen.kind === 'end' && (
          <div className="wizard-section-screen">
            <h2 className="wizard-section-title">Llegaste al final</h2>
            <p className="wizard-section-desc">
              Revisá tus respuestas con &quot;Anterior&quot; si querés corregir algo, o enviá la
              encuesta cuando estés listo/a.
            </p>
          </div>
        )}
      </main>

      <div className="wizard-bottombar">
        <button
          type="button"
          className="btn btn-secondary"
          onClick={handleBack}
          disabled={idx === 0 || isPending}
          aria-disabled={idx === 0 || isPending}
        >
          Anterior
        </button>
        <span className="wizard-bottombar-hint" aria-hidden="true">
          {ordinal}/{questionScreens.length}
        </span>
        {screen.kind !== 'end' ? (
          <button type="button" className="btn btn-primary" onClick={handleNext}>
            Siguiente
          </button>
        ) : (
          <button
            type="button"
            className="btn btn-primary"
            onClick={handleSubmit}
            disabled={isPending}
            aria-disabled={isPending}
          >
            {isPending ? 'Enviando…' : 'Enviar encuesta'}
          </button>
        )}
      </div>
    </div>
  )
}
