/**
 * Utilidades de validación de formularios de contratos (cliente + CUPS).
 */

export type SeccionSuministroContrato = 'electrico' | 'gas';

export type TabMultipuntoContrato = 'electricoTab' | 'gasTab';

export const EVENTO_ACTIVAR_PESTANA_SUMINISTRO = 'eneon:activar-pestaña-suministro';

export const EVENTO_ACTIVAR_TAB_MULTIPUNTO = 'eneon:activar-tab-multipunto';

export interface OpcionesEnfoqueCampoFormulario {
    seccionSuministro?: SeccionSuministroContrato;
    tabMultipunto?: TabMultipuntoContrato;
    contenedorScroll?: string | HTMLElement;
}

export interface OpcionesValidacionInline extends OpcionesEnfoqueCampoFormulario {}

export function obtenerIdDomCeldaTabla(
    tipo: 'electrico' | 'gas',
    rowIndex: number,
    campo: string,
): string {
    return `${tipo}-fila-${rowIndex}-${campo}`;
}

const RETRASOS_ENFOQUE_MS = [0, 80, 200, 400] as const;
const MARGEN_SCROLL_ENFOQUE = '6rem';

export function esValorCampoVacio(valor: unknown): boolean {
    return (
        valor === null
        || valor === undefined
        || (typeof valor === 'string' && valor.trim() === '')
    );
}

/** Resuelve alias habituales (p. ej. localidad ↔ DesLoc). */
export function obtenerValorCampoContrato(fila: Record<string, unknown>, campo: string): unknown {
    const alias: Record<string, string[]> = {
        localidad: ['localidad', 'DesLoc'],
        provincia: ['provincia', 'DesPro'],
        localidadGas: ['localidadGas', 'DesLoc'],
        provinciaGas: ['provinciaGas', 'DesPro'],
    };

    const claves = alias[campo] ?? [campo];

    for (const clave of claves) {
        const valor = fila[clave];
        if (!esValorCampoVacio(valor)) {
            return valor;
        }
    }

    return fila[campo];
}

export function construirErroresCamposObligatorios(
    datos: Record<string, unknown>,
    camposOrdenados: string[],
    etiquetas: Record<string, string>,
): Record<string, string> {
    const errores: Record<string, string> = {};

    for (const campo of camposOrdenados) {
        if (esValorCampoVacio(obtenerValorCampoContrato(datos, campo))) {
            const etiqueta = etiquetas[campo] ?? campo;
            errores[campo] = `El campo ${etiqueta} es obligatorio.`;
        }
    }

    return errores;
}

export function obtenerPrimerCampoConError(
    errores: Record<string, string>,
    camposOrdenados: string[],
): string | null {
    for (const campo of camposOrdenados) {
        if (errores[campo]) {
            return campo;
        }
    }

    return null;
}

export function resolverIdDomCampo(
    campo: string,
    mapa: Record<string, string>,
): string {
    return mapa[campo] ?? campo;
}

function activarTabMultipuntoSiAplica(tabId?: TabMultipuntoContrato): void {
    if (!tabId || typeof window === 'undefined') {
        return;
    }

    window.dispatchEvent(
        new CustomEvent<{ tabId: TabMultipuntoContrato }>(EVENTO_ACTIVAR_TAB_MULTIPUNTO, {
            detail: { tabId },
        }),
    );
}

function normalizarOpcionesEnfoque(
    opciones?: OpcionesEnfoqueCampoFormulario | SeccionSuministroContrato,
): OpcionesEnfoqueCampoFormulario {
    if (!opciones) {
        return {};
    }

    if (typeof opciones === 'string') {
        return { seccionSuministro: opciones };
    }

    return opciones;
}

function resolverContenedorScroll(opciones: OpcionesEnfoqueCampoFormulario): HTMLElement | null {
    if (!opciones.contenedorScroll || typeof document === 'undefined') {
        return null;
    }

    if (typeof opciones.contenedorScroll === 'string') {
        return document.querySelector<HTMLElement>(opciones.contenedorScroll);
    }

    return opciones.contenedorScroll;
}

function activarPestañaSuministroSiAplica(seccion?: SeccionSuministroContrato): void {
    if (!seccion || typeof window === 'undefined') {
        return;
    }

    window.dispatchEvent(
        new CustomEvent<{ seccion: SeccionSuministroContrato }>(EVENTO_ACTIVAR_PESTANA_SUMINISTRO, {
            detail: { seccion },
        }),
    );
}

function obtenerElementoReferencia(idDom: string, contenedor?: HTMLElement | null): HTMLElement | null {
    if (!idDom || typeof document === 'undefined') {
        return null;
    }

    if (contenedor) {
        return contenedor.querySelector<HTMLElement>(`#${CSS.escape(idDom)}`);
    }

    return document.getElementById(idDom);
}

function obtenerInputEnfocable(referencia: HTMLElement): HTMLElement {
    const contenedorTypeahead = referencia.closest('.rbt');

    if (contenedorTypeahead) {
        const inputTypeahead = contenedorTypeahead.querySelector<HTMLElement>(
            'input.rbt-input-main, input.form-control',
        );

        if (inputTypeahead) {
            return inputTypeahead;
        }
    }

    const esFlatpickrOculto =
        referencia.classList.contains('flatpickr-input')
        || (referencia instanceof HTMLInputElement && referencia.type === 'hidden');

    if (esFlatpickrOculto) {
        const contenedorFlatpickr = referencia.closest('.flatpickr-wrapper') ?? referencia.parentElement;
        const inputVisible = contenedorFlatpickr?.querySelector<HTMLElement>(
            'input.form-control:not([type="hidden"])',
        );

        if (inputVisible) {
            return inputVisible;
        }
    }

    if (
        referencia.matches('input, select, textarea, button')
        || referencia.matches('[tabindex]:not([tabindex="-1"])')
    ) {
        return referencia;
    }

    const descendienteEnfocable = referencia.querySelector<HTMLElement>(
        'input, select, textarea, button, [tabindex]:not([tabindex="-1"])',
    );

    return descendienteEnfocable ?? referencia;
}

function obtenerContenedorScroll(elemento: HTMLElement): HTMLElement {
    return (
        elemento.closest('td')
        ?? elemento.closest('.col')
        ?? elemento.closest('.input-group')
        ?? elemento.closest('.form-group')
        ?? elemento
    );
}

/** Desplaza la vista y transfiere el foco al campo indicado por su id DOM. */
export function desplazarYEnfocarCampo(
    idDom: string,
    opciones: OpcionesEnfoqueCampoFormulario = {},
): boolean {
    const contenedorScroll = resolverContenedorScroll(opciones);
    const referencia = obtenerElementoReferencia(idDom, contenedorScroll);

    if (!referencia) {
        return false;
    }

    const objetivoScroll = obtenerContenedorScroll(referencia);
    objetivoScroll.style.scrollMarginTop = MARGEN_SCROLL_ENFOQUE;
    objetivoScroll.style.scrollMarginBottom = '1rem';
    objetivoScroll.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });

    const objetivoFoco = obtenerInputEnfocable(referencia);

    if (typeof objetivoFoco.focus === 'function') {
        objetivoFoco.focus({ preventScroll: true });
    }

    return true;
}

/** Programa scroll/foco tras el commit de React y reintentos por componentes asíncronos (Flatpickr, etc.). */
export function programarEnfoqueCampoFormulario(
    idDom: string,
    opciones?: OpcionesEnfoqueCampoFormulario | SeccionSuministroContrato,
): void {
    if (!idDom) {
        return;
    }

    const opcionesNormalizadas = normalizarOpcionesEnfoque(opciones);

    activarPestañaSuministroSiAplica(opcionesNormalizadas.seccionSuministro);
    activarTabMultipuntoSiAplica(opcionesNormalizadas.tabMultipunto);

    const intentarEnfoque = (): void => {
        desplazarYEnfocarCampo(idDom, opcionesNormalizadas);
    };

    requestAnimationFrame(() => {
        requestAnimationFrame(() => {
            RETRASOS_ENFOQUE_MS.forEach((retraso) => {
                window.setTimeout(intentarEnfoque, retraso);
            });
        });
    });
}

/** @deprecated Usar programarEnfoqueCampoFormulario */
export function enfocarCampoFormulario(idDom: string): void {
    programarEnfoqueCampoFormulario(idDom);
}

export const IDS_DOM_CAMPOS_ELECTRICO: Record<string, string> = {
    comercializadora: 'electrico-comercializadora',
    producto: 'electrico-producto',
    anexo: 'electrico-anexo',
    tipoprecio: 'electrico-tipoPrecio',
    cups_electrico: 'cups_electrico',
    tarifa: 'tarifa',
    direccion: 'electrico-direccion',
    localidad: 'electrico-localidad',
    provincia: 'electrico-provincia',
    codigo_postal: 'electrico-codigo-postal',
    consumo_kw: 'consumo_kw',
    fechaInicio: 'electrico-inicio',
    fechaFin: 'electrico-fin',
};

export const IDS_DOM_CAMPOS_GAS: Record<string, string> = {
    comercializadora: 'gas-comercializadora',
    producto: 'gas-producto',
    anexo: 'gas-anexo',
    tipoprecio: 'gas-tipoPrecio',
    cupsGas: 'cupsGas',
    tarifaGas: 'tarifaGas',
    direccionGas: 'gas-direccion',
    localidadGas: 'gas-localidad',
    provinciaGas: 'gas-provincia',
    codigo_postal: 'gas-codigo-postal',
    consumoGas: 'consumoGas',
    caudal_diario: 'caudal_diario',
    fechaInicio: 'gas-inicio',
    fechaFin: 'gas-fin',
};

export function aplicarValidacionInline(
    errores: Record<string, string>,
    camposOrdenados: string[],
    mapaIdsDom: Record<string, string>,
    opciones: OpcionesValidacionInline = {},
): string | null {
    const primerCampo = obtenerPrimerCampoConError(errores, camposOrdenados);

    if (!primerCampo) {
        return null;
    }

    const idDom = resolverIdDomCampo(primerCampo, mapaIdsDom);
    programarEnfoqueCampoFormulario(idDom, opciones);

    return idDom;
}
