'use client';
import React, {
  createContext,
  useContext,
  useReducer,
  useEffect,
  useRef,
  useMemo,
  useCallback,
  ReactNode,
} from 'react';
import axiosInstance from '@/utils/api-config';
import { getAxiosError } from '@/utils/errors-utils';
import { GetCuestionario } from '@/types/evento';
import { UsuarioDataResponse } from '@/containers/formulario/formulario-registro';
import {
  formularioReducer,
  initialState,
  FormularioState,
  RespuestaFormulario,
} from './formulario-reducer';

// ── Longitudes requeridas por tipo de validación ─────────────────────────────

const LONGITUDES: Record<string, number> = {
  cuenta_alumno: 9,
  cuenta_trabajador: 6,
  rfc: 10,
};

// ── Tipos del contexto ────────────────────────────────────────────────────────

interface FormularioContextType {
  state: FormularioState;

  // Datos derivados estables
  preguntas: ReturnType<typeof getPreguntasFlat>;
  preguntaComunidad: PreguntaFlat | undefined;
  preguntaCuenta: PreguntaFlat | undefined;
  esComunidadSi: boolean;
  esExclusivo: boolean;
  mostrarFormularioCompleto: boolean;

  // Acciones
  setRespuesta: (id: string, valor: string) => void;
  submitFormulario: (id_cuestionario: number) => Promise<import('@/types/submit').SubmitResponse>;
}

// Helper para aplanar preguntas
type PreguntaFlat = GetCuestionario['cuestionario']['secciones'][0]['preguntas'][0]['pregunta'];

function getPreguntasFlat(data: GetCuestionario | null): PreguntaFlat[] {
  if (!data) return [];
  return data.cuestionario.secciones.flatMap((s) =>
    s.preguntas.map((p) => p.pregunta)
  );
}

// ── Context ───────────────────────────────────────────────────────────────────

const FormularioContext = createContext<FormularioContextType | undefined>(undefined);

interface FormularioProviderProps {
  children: ReactNode;
  id_evento: number;
  id_cuestionario: number;
}

export function FormularioProvider({
  children,
  id_evento,
  id_cuestionario,
}: FormularioProviderProps) {
  const [state, dispatch] = useReducer(formularioReducer, initialState);
  // Rastrea si ya se limpiaron los campos para el usuarioEncontrado actual
  const yaLimpioRef = useRef(false);

  // ── Carga del cuestionario ─────────────────────────────────────────────────

  useEffect(() => {
    dispatch({ type: 'FETCH_DATA_START' });
    axiosInstance
      .get<GetCuestionario>(`/cuestionario/${id_cuestionario}/formulario`)
      .then((res) => dispatch({ type: 'FETCH_DATA_SUCCESS', payload: res.data }))
      .catch((err) => {
        const { message } = getAxiosError(err);
        dispatch({ type: 'FETCH_DATA_ERROR', payload: message });
      });
  }, [id_cuestionario]);

  // ── Derivados estables ─────────────────────────────────────────────────────

  const preguntas = useMemo(() => getPreguntasFlat(state.data), [state.data]);

  const preguntaComunidad = useMemo(
    () =>
      preguntas.find(
        (p) =>
          p.validacion === 'comunidad_alumno' ||
          p.validacion === 'comunidad_trabajador'
      ),
    [preguntas]
  );

  const preguntaCuenta = useMemo(
    () =>
      preguntas.find(
        (p) =>
          p.validacion === 'cuenta_alumno' ||
          p.validacion === 'cuenta_trabajador' ||
          p.validacion === 'rfc'
      ),
    [preguntas]
  );

  const comunidadSeleccionada = preguntaComunidad
    ? state.respuestas[preguntaComunidad.id_pregunta]
    : null;

  const esComunidadSi = useMemo(
    () =>
      !!(
        comunidadSeleccionada &&
        preguntaComunidad?.opciones.find(
          (op) =>
            op.id_opcion === Number(comunidadSeleccionada) &&
            op.opcion.opcion.toLowerCase().includes('si')
        )
      ),
    [comunidadSeleccionada, preguntaComunidad]
  );

  const esExclusivo = useMemo(
    () => !preguntaComunidad && !!preguntaCuenta,
    [preguntaComunidad, preguntaCuenta]
  );

  const mostrarFormularioCompleto =
    (esExclusivo && state.busquedaCompletada) ||
    (!preguntaComunidad && !esExclusivo) ||
    (esComunidadSi && state.busquedaCompletada) ||
    (!!(esComunidadSi === false) && !!comunidadSeleccionada);

  // ── Búsqueda de cuenta ─────────────────────────────────────────────────────

  useEffect(() => {
    const debeIniciarBusqueda = preguntaCuenta && (esExclusivo || esComunidadSi);

    if (!debeIniciarBusqueda) {
      if (state.cuentaBuscada || state.busquedaCompletada || state.errorBusqueda) {
        dispatch({ type: 'BUSQUEDA_RESET' });
      }
      return;
    }

    const cuenta = state.respuestas[preguntaCuenta.id_pregunta];
    if (!cuenta || typeof cuenta !== 'string') {
      if (state.cuentaBuscada || state.busquedaCompletada || state.errorBusqueda) {
        dispatch({ type: 'BUSQUEDA_RESET' });
      }
      return;
    }

    const longitudRequerida = LONGITUDES[preguntaCuenta.validacion ?? ''];
    if (!longitudRequerida || cuenta.length !== longitudRequerida) {
      if (state.cuentaBuscada) dispatch({ type: 'BUSQUEDA_RESET' });
      return;
    }

    // No re-buscar la misma cuenta
    if (cuenta === state.cuentaBuscada) return;

    let endpoint =
      preguntaCuenta.validacion === 'cuenta_alumno'
        ? `/alumnos/${cuenta}`
        : `/trabajadores/${cuenta}`;

    if (esExclusivo) endpoint += `?id_evento=${id_evento}`;

    dispatch({ type: 'BUSQUEDA_START', payload: cuenta });

    axiosInstance
      .get<UsuarioDataResponse>(endpoint)
      .then((res) => {
        const d = res.data;
        if (d.nombre || d.apellidos || d.carrera || d.genero) {
          dispatch({ type: 'BUSQUEDA_SUCCESS', payload: d });
        } else {
          dispatch({ type: 'BUSQUEDA_ERROR', payload: 'No se encontraron datos para este usuario' });
        }
      })
      .catch((err) => {
        const { message } = getAxiosError(err);
        dispatch({ type: 'BUSQUEDA_ERROR', payload: message });
      });
  }, [
    state.respuestas,
    state.cuentaBuscada,
    state.busquedaCompletada,
    state.errorBusqueda,
    preguntaCuenta,
    esComunidadSi,
    esExclusivo,
    id_evento,
  ]);

  // ── Autorelleno cuando llega usuarioEncontrado ─────────────────────────────

  useEffect(() => {
    if (!state.data) return;

    if (!state.usuarioEncontrado) {
      // Solo limpiar si aún no lo hicimos (evita loop infinito)
      if (!yaLimpioRef.current) return;
      yaLimpioRef.current = false;
      const idsCampos = preguntas
        .filter((p) =>
          ['nombre', 'apellidos', 'correo', 'carrera', 'genero'].includes(p.validacion ?? '')
        )
        .map((p) => p.id_pregunta);
      if (idsCampos.length) {
        dispatch({ type: 'LIMPIAR_CAMPOS_AUTORELLENO', payload: idsCampos });
      }
      return;
    }

    const u = state.usuarioEncontrado;
    const bulk: RespuestaFormulario = {};

    preguntas.forEach((pregunta) => {
      const id = pregunta.id_pregunta;
      switch (pregunta.validacion) {
        case 'nombre':
          bulk[id] = u.nombre ?? '';
          break;
        case 'apellidos':
          bulk[id] = u.apellidos ?? '';
          break;
        case 'correo':
          bulk[id] = u.cuenta ? `${u.cuenta}@pcpuma.acatlan.unam.mx` : '';
          break;
        case 'carrera':
          bulk[id] = u.carrera ?? '';
          break;
        case 'genero': {
          const texto = u.genero === 'M' ? 'Masculino' : 'Femenino';
          const opcion = pregunta.opciones?.find(
            (op) => op.opcion.opcion.toLowerCase() === texto.toLowerCase()
          );
          if (opcion) bulk[id] = String(opcion.id_opcion);
          break;
        }
      }
    });

    if (Object.keys(bulk).length) {
      yaLimpioRef.current = true;
      dispatch({ type: 'SET_RESPUESTAS_BULK', payload: bulk });
    }
  }, [state.usuarioEncontrado, state.data, preguntas]);

  // ── Acciones expuestas ─────────────────────────────────────────────────────

  const setRespuesta = useCallback((id: string, valor: string) => {
    dispatch({ type: 'SET_RESPUESTA', payload: { id, valor } });
  }, []);

  const submitFormulario = useCallback(
    async (id_cuestionario: number) => {
      dispatch({ type: 'SEND_START' });
      try {
        const preguntaCorreo = preguntas.find(
          (p) => p.validacion === 'correo' || p.validacion === 'correo_institucional'
        );
        let correo = preguntaCorreo
          ? String(state.respuestas[preguntaCorreo.id_pregunta] ?? '')
          : '';
        if (!correo) {
          const rx = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
          for (const v of Object.values(state.respuestas)) {
            if (typeof v === 'string' && rx.test(v)) { correo = v; break; }
          }
        }

        const res = await axiosInstance.post<import('@/types/submit').SubmitResponse>(
          '/cuestionario-respondido/submit',
          {
            id_cuestionario,
            correo,
            fecha_envio: new Date().toISOString(),
            respuestas: Object.entries(state.respuestas).map(([id, valor]) => ({
              id_pregunta: Number(id),
              valor: isNaN(Number(valor)) ? valor : Number(valor),
            })),
          }
        );
        return res.data;
      } finally {
        dispatch({ type: 'SEND_END' });
      }
    },
    [state.respuestas, preguntas]
  );

  // ── Valor del contexto ─────────────────────────────────────────────────────

  const value: FormularioContextType = {
    state,
    preguntas,
    preguntaComunidad,
    preguntaCuenta,
    esComunidadSi,
    esExclusivo,
    mostrarFormularioCompleto,
    setRespuesta,
    submitFormulario,
  };

  return (
    <FormularioContext.Provider value={value}>
      {children}
    </FormularioContext.Provider>
  );
}

export function useFormulario() {
  const ctx = useContext(FormularioContext);
  if (!ctx) throw new Error('useFormulario debe usarse dentro de FormularioProvider');
  return ctx;
}
