document.addEventListener('DOMContentLoaded', () => {
    const state = {
        mode: 'day',
        resolution: '24',
        marketType: 'omie_pt',
        chart: null,
        currentChartRows: [],
    };

    const els = {
        fechaInicio: document.getElementById('fecha_inicio'),
        fechaFin: document.getElementById('fecha_fin'),
        fechaSelect: document.getElementById('fecha_select'),
        tipoConsulta: document.getElementById('tipo_consulta'),
        openConsultaInfo: document.getElementById('openConsultaInfo'),
        consultaInfoTitle: document.getElementById('consultaInfoTitle'),
        consultaInfoDesc: document.getElementById('consultaInfoDesc'),
        consultaInfoSource: document.getElementById('consultaInfoSource'),
        consultaInfoFields: document.getElementById('consultaInfoFields'),
        filtrar: document.getElementById('filtrar'),
        reset: document.getElementById('reset'),
        mostrarDia: document.getElementById('mostrarDia'),
        mostrarMes: document.getElementById('mostrarMes'),
        mostrarAnio: document.getElementById('mostrarAnio'),
        resolution24: document.getElementById('resolution24'),
        resolution96: document.getElementById('resolution96'),
        chartTitle: document.getElementById('chartTitle'),
        chartSubtitle: document.getElementById('chartSubtitle'),
        chartMeta: document.getElementById('chartMeta'),
        alertsSummary: document.getElementById('alertsSummary'),
        alertsList: document.getElementById('alertsList'),
        refreshAlerts: document.getElementById('refreshAlerts'),
        resultados: document.getElementById('resultados'),
        resultsPagination: document.getElementById('resultsPagination'),
        detailSection: document.getElementById('detailSection'),
        detalle: document.getElementById('detalle'),
        toggleDetalle: document.getElementById('toggleDetalle'),
        exportChart: document.getElementById('exportChart'),
        exportTable: document.getElementById('exportTable'),
        chartCanvas: document.getElementById('graficaPrecios'),
    };

    const metricFields = {
        dailyAverage: document.querySelector('[data-metric="daily-average"]'),
        dailyAverageFoot: document.querySelector('[data-metric-foot="daily-average"]'),
        dailyRange: document.querySelector('[data-metric="daily-range"]'),
        dailyMin: document.querySelector('[data-metric="daily-min"]'),
        dailyMax: document.querySelector('[data-metric="daily-max"]'),
        dailyRangeFoot: document.querySelector('[data-metric-foot="daily-range"]'),
        monthAverage: document.querySelector('[data-metric="month-average"]'),
        monthAverageFoot: document.querySelector('[data-metric-foot="month-average"]'),
        yearAverage: document.querySelector('[data-metric="year-average"]'),
        yearAverageFoot: document.querySelector('[data-metric-foot="year-average"]'),
        integrity24: document.querySelector('[data-metric="integrity-24"]'),
        integrity24Foot: document.querySelector('[data-metric-foot="integrity-24"]'),
        integrity96: document.querySelector('[data-metric="integrity-96"]'),
        integrity96Foot: document.querySelector('[data-metric-foot="integrity-96"]'),
    };

    const today = new Date().toISOString().split('T')[0];
    els.fechaSelect.value = today;
    els.fechaInicio.value = today.slice(0, 8) + '01';
    els.fechaFin.value = today;

    const consultaInfoMap = {
        precio_medio: {
            title: 'Comparativa OMIE y horas solar',
            desc: 'Compara el precio medio diario OMIE con el precio medio diario de horas solar para el rango seleccionado.',
            source: 'Consulta BD: OMIE_PRE y LIST_OMIE_PM_HR_SOLARES',
            fields: 'Muestra: medias diarias, mensuales y anuales, con exportacion por dia.',
        },
        precio_solar: {
            title: 'Precio medio horas solar',
            desc: 'Consulta el precio medio diario solar y calcula tambien la media mensual y anual del mismo conjunto solar.',
            source: 'Consulta BD: LIST_OMIE_PM_HR_SOLARES',
            fields: 'Muestra: precio medio diario, mensual y anual de horas solar.',
        },
        precio_tarifa: {
            title: 'Precio medio por tarifa',
            desc: 'Resume el coste medio, minimo y maximo por tarifa para el rango seleccionado.',
            source: 'Consulta BD: BICUBO_COSTE_HORA',
            fields: 'Muestra: precio medio, precio minimo y precio maximo por tarifa.',
        },
        consumo_tarifa: {
            title: 'Consumo por tarifa',
            desc: 'Agrupa el consumo total registrado por tarifa dentro del rango de fechas indicado.',
            source: 'Consulta BD: bd_apis.dbo.metering',
            fields: 'Muestra: consumo total acumulado por tarifa en MWh.',
        },
    };

    function updateConsultaInfo() {
        const info = consultaInfoMap[els.tipoConsulta.value] || consultaInfoMap.precio_medio;
        els.consultaInfoTitle.textContent = info.title;
        els.consultaInfoDesc.textContent = info.desc;
        els.consultaInfoSource.textContent = info.source;
        els.consultaInfoFields.textContent = info.fields;
    }

    function toMWh(value) {
        if (value === null || value === undefined || Number.isNaN(Number(value))) {
            return null;
        }

        return Number(value) * 1000;
    }

    function formatDateDisplay(dateString) {
        const date = new Date(dateString + 'T00:00:00');
        return date.toLocaleDateString('es-ES');
    }

    function formatCurrency(value, decimals = 2, withUnit = true) {
        const converted = toMWh(value);
        if (converted === null) {
            return '--';
        }

        const formatted = converted.toLocaleString('es-ES', {
            minimumFractionDigits: decimals,
            maximumFractionDigits: decimals,
        });

        return withUnit ? `${formatted} EUR/MWh` : formatted;
    }

    function formatCompact(value, decimals = 2) {
        const converted = toMWh(value);
        if (converted === null) {
            return '--';
        }

        return converted.toLocaleString('es-ES', {
            minimumFractionDigits: decimals,
            maximumFractionDigits: decimals,
        });
    }

    function formatMWhValue(value, decimals = 2, withUnit = true) {
        if (value === null || value === undefined || Number.isNaN(Number(value))) {
            return '--';
        }

        const formatted = Number(value).toLocaleString('es-ES', {
            minimumFractionDigits: decimals,
            maximumFractionDigits: decimals,
        });

        return withUnit ? `${formatted} EUR/MWh` : formatted;
    }

    function downloadExcel(filename, rows, sheetName = 'Datos') {
        if (!window.XLSX) {
            throw new Error('La libreria de Excel no esta disponible.');
        }

        const workbook = XLSX.utils.book_new();
        const worksheet = XLSX.utils.aoa_to_sheet(rows);
        XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
        XLSX.writeFile(workbook, filename);
    }

    async function postForm(url, payload, responseType = 'json') {
        const response = await fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' },
            body: new URLSearchParams(payload),
        });

        if (responseType === 'text') {
            if (!response.ok) {
                throw new Error(`Error ${response.status} al consultar ${url}`);
            }
            return response.text();
        }

        const data = await response.json();
        if (!response.ok) {
            throw new Error(data.error || `Error ${response.status} al consultar ${url}`);
        }

        return data;
    }

    function setSegmentedState(activeButton, allButtons) {
        allButtons.forEach((button) => {
            const active = button === activeButton;
            button.classList.toggle('is-active', active);
            if (button.id.includes('resolution')) {
                button.classList.toggle('btn-success', active);
                button.classList.toggle('btn-outline-success', !active);
            } else {
                button.classList.toggle('btn-primary', active);
                button.classList.toggle('btn-outline-primary', !active);
            }
        });
    }

    function destroyChart() {
        if (state.chart) {
            state.chart.destroy();
            state.chart = null;
        }
    }

    function updateChartMeta(items) {
        els.chartMeta.innerHTML = items
            .map((item) => `<span class="meta-chip ${item.type || ''}">${item.label}</span>`)
            .join('');
    }

    function showNoDataState(message) {
        destroyChart();
        els.chartTitle.textContent = 'Sin datos para la fecha seleccionada';
        els.chartSubtitle.textContent = message;
        updateChartMeta([{ label: message, type: 'warning' }]);

        metricFields.dailyAverage.textContent = '--';
        metricFields.dailyAverageFoot.textContent = 'Sin datos';
        metricFields.dailyRange.textContent = 'Rango del dia';
        metricFields.dailyMin.textContent = 'Min: --';
        metricFields.dailyMax.textContent = 'Max: --';
        metricFields.dailyRangeFoot.textContent = 'Sin datos';
        metricFields.monthAverage.textContent = '--';
        metricFields.monthAverageFoot.textContent = 'Sin datos';
        metricFields.yearAverage.textContent = '--';
        metricFields.yearAverageFoot.textContent = 'Sin datos';
        metricFields.integrity24.textContent = '--';
        metricFields.integrity24Foot.textContent = 'Sin datos';
        metricFields.integrity96.textContent = '--';
        metricFields.integrity96Foot.textContent = 'Sin datos';
        state.currentChartRows = [];
    }

    function revealDetailSection(scroll = false) {
        els.detailSection.classList.remove('d-none');
        els.toggleDetalle.classList.remove('d-none');
        els.detalle.style.display = 'block';
        els.toggleDetalle.textContent = 'Ocultar detalle';

        if (scroll) {
            els.detailSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }
    }

    function renderChart({ type, labels, datasets, title, subtitle, meta = [] }) {
        destroyChart();
        els.chartTitle.textContent = title;
        els.chartSubtitle.textContent = subtitle;
        updateChartMeta(meta);

        state.chart = new Chart(els.chartCanvas.getContext('2d'), {
            type,
            data: { labels, datasets },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                interaction: {
                    intersect: false,
                    mode: 'index',
                },
                plugins: {
                    legend: {
                        display: datasets.length > 1,
                        position: 'top',
                    },
                    tooltip: {
                        callbacks: {
                            label(context) {
                                const value = context.raw;
                                if (value === null || value === undefined) {
                                    return `${context.dataset.label}: sin dato`;
                                }
                                return `${context.dataset.label}: ${formatMWhValue(value, 2)}`;
                            },
                        },
                    },
                },
                scales: {
                    x: {
                        title: {
                            display: true,
                            text: state.mode === 'day'
                                ? (state.resolution === '96' ? 'Periodo cuartohorario' : 'Periodo')
                                : (state.mode === 'month' ? 'Dia del mes' : 'Mes'),
                            color: '#12304f',
                            font: {
                                size: 14,
                                weight: '600',
                            },
                        },
                    },
                    y: {
                        beginAtZero: true,
                        ticks: {
                            callback(value) {
                                return formatMWhValue(value, 2);
                            },
                        },
                    },
                },
            },
        });
    }

    function buildChartRows(labels, values) {
        return [['Etiqueta', 'Precio (EUR/MWh)']].concat(
            labels.map((label, index) => [label, values[index] === null ? '' : Number(toMWh(values[index]).toFixed(2))])
        );
    }

    function renderDashboard(summary) {
        const day = summary.dia || {};
        const quarter = summary.cuartoHora || {};
        const month = summary.mes || {};
        const year = summary.anio || {};

        metricFields.dailyAverage.textContent = formatCurrency(day.average, 2, false);
        metricFields.dailyAverageFoot.textContent = `${formatDateDisplay(summary.fecha)} · ${day.loadedPoints || 0}/${day.expectedPoints || 24} puntos`;

        metricFields.dailyRange.textContent = 'Rango del dia';
        metricFields.dailyMin.textContent = `Min: ${formatCompact(day.min, 2)}`;
        metricFields.dailyMax.textContent = `Max: ${formatCompact(day.max, 2)}`;
        metricFields.dailyRangeFoot.textContent = 'Minimo y maximo del dia';

        metricFields.monthAverage.textContent = formatCurrency(month.average, 2, false);
        metricFields.monthAverageFoot.textContent = `${month.loadedDays || 0}/${month.expectedDays || 0} dias cargados`;

        metricFields.yearAverage.textContent = formatCurrency(year.average, 2, false);
        metricFields.yearAverageFoot.textContent = `${year.loadedDays || 0}/${year.expectedDays || 0} dias cargados`;

        metricFields.integrity24.textContent = `${day.loadedPoints || 0}/${day.expectedPoints || 24}`;
        metricFields.integrity24Foot.textContent = day.missingPoints > 0
            ? `${day.missingPoints} horas sin cargar`
            : 'Todas las horas cargadas';

        metricFields.integrity96.textContent = `${quarter.loadedPoints || 0}/${quarter.expectedPoints || 96}`;
        metricFields.integrity96Foot.textContent = quarter.missingPoints > 0
            ? `${quarter.missingPoints} cuartos sin cargar`
            : 'Todos los cuartos cargados';
    }

    function renderAlerts(data) {
        const total24 = data.missing24.length;
        const total96 = data.missing96.length;
        const duplicates = data.duplicates.length;

        els.alertsSummary.innerHTML = `
            <div class="d-flex flex-wrap gap-2">
                <span class="alert-chip ${total24 ? 'warning' : 'success'}">24h con huecos: ${total24}</span>
                <span class="alert-chip ${total96 ? 'warning' : 'success'}">15 min con huecos: ${total96}</span>
                <span class="alert-chip ${duplicates ? 'warning' : 'success'}">Fechas multi-tipo: ${duplicates}</span>
            </div>
        `;

        const entries = [];

        data.missing24.slice(0, 5).forEach((item) => {
            entries.push({
                title: `${formatDateDisplay(item.fecha)} · vista 24h`,
                body: `${item.missingPoints} horas sin cargar.`,
            });
        });

        data.missing96.slice(0, 5).forEach((item) => {
            entries.push({
                title: `${formatDateDisplay(item.fecha)} · vista 15 min`,
                body: `${item.missingPoints} cuartos sin cargar.`,
            });
        });

        data.duplicates.slice(0, 5).forEach((item) => {
            entries.push({
                title: `${formatDateDisplay(item.fecha)} · varias variantes`,
                body: `La vista devuelve ${item.totalRows} filas para la misma fecha, normalmente por tipos como omie y omie_pt.`,
            });
        });

        if (entries.length === 0) {
            els.alertsList.innerHTML = `
                <div class="alert-item">
                    <strong>Sin alertas en el rango</strong>
                    <span>No se detectaron huecos de carga ni duplicados para el rango consultado.</span>
                </div>
            `;
            return;
        }

        els.alertsList.innerHTML = entries
            .map((entry) => `
                <div class="alert-item">
                    <strong>${entry.title}</strong>
                    <span>${entry.body}</span>
                </div>
            `)
            .join('');
    }

    function clearResultsPagination() {
        els.resultsPagination.innerHTML = '';
        els.resultsPagination.classList.add('d-none');
    }

    function paginateResultsTable() {
        clearResultsPagination();

        const table = els.resultados.querySelector('table');
        if (!table) {
            return;
        }

        const body = table.querySelector('tbody');
        if (!body) {
            return;
        }

        const rows = Array.from(body.querySelectorAll('tr'));
        const dataRows = rows.filter((row) => row.querySelectorAll('td').length > 1);
        const pageSize = 10;

        if (dataRows.length <= pageSize) {
            return;
        }

        let currentPage = 1;
        const totalPages = Math.ceil(dataRows.length / pageSize);

        els.resultsPagination.classList.remove('d-none');
        els.resultsPagination.innerHTML = `
            <button type="button" class="btn btn-outline-secondary btn-sm" data-results-page="prev">Anterior</button>
            <span class="results-pagination-info"></span>
            <button type="button" class="btn btn-outline-secondary btn-sm" data-results-page="next">Siguiente</button>
        `;

        const info = els.resultsPagination.querySelector('.results-pagination-info');
        const prevButton = els.resultsPagination.querySelector('[data-results-page="prev"]');
        const nextButton = els.resultsPagination.querySelector('[data-results-page="next"]');

        function renderPage(page) {
            currentPage = page;
            const start = (page - 1) * pageSize;
            const end = start + pageSize;

            dataRows.forEach((row, index) => {
                row.style.display = index >= start && index < end ? '' : 'none';
            });

            info.textContent = `Registros ${start + 1}-${Math.min(end, dataRows.length)} de ${dataRows.length}`;
            prevButton.disabled = currentPage === 1;
            nextButton.disabled = currentPage === totalPages;
        }

        prevButton.addEventListener('click', () => {
            if (currentPage > 1) {
                renderPage(currentPage - 1);
            }
        });

        nextButton.addEventListener('click', () => {
            if (currentPage < totalPages) {
                renderPage(currentPage + 1);
            }
        });

        renderPage(1);
    }

    async function loadAlerts() {
        const payload = {
            fecha_inicio: els.fechaInicio.value || today.slice(0, 8) + '01',
            fecha_fin: els.fechaFin.value || today,
            market_type: state.marketType,
        };

        try {
            const data = await postForm('ajax/get_integrity_alerts.php', payload);
            renderAlerts(data);
        } catch (error) {
            els.alertsList.innerHTML = `<div class="alert-item"><strong>Error</strong><span>${error.message}</span></div>`;
        }
    }

    async function loadDashboardSummary(date) {
        const summary = await postForm('ajax/get_dashboard_summary.php', {
            fecha: date,
            market_type: state.marketType,
        });
        renderDashboard(summary);
    }

    async function loadDayChart(date) {
        const data = await postForm('ajax/get_precios_por_fecha.php', {
            fecha: date,
            resolution: state.resolution,
            market_type: state.marketType,
        });

        const color = state.resolution === '96'
            ? { border: 'rgba(30, 157, 99, 1)', background: 'rgba(30, 157, 99, 0.18)' }
            : { border: 'rgba(10, 132, 255, 1)', background: 'rgba(10, 132, 255, 0.18)' };

        renderChart({
            type: 'bar',
            labels: data.labels,
            datasets: [{
                label: state.resolution === '96' ? 'Precio por cuarto de hora' : 'Precio por hora',
                data: data.prices.map((value) => toMWh(value)),
                borderColor: color.border,
                backgroundColor: color.background,
                borderWidth: 1,
            }],
            title: `Precio del mercado diario`,
            subtitle: state.resolution === '96'
                ? `${formatDateDisplay(date)} · Vista de 96 cuartos de hora desde vw_OMIE_PRE_96`
                : `${formatDateDisplay(date)} · Vista horaria de 24 puntos desde vw_OMIE_PRE_24`,
            meta: [
                { label: `Media: ${formatCurrency(data.stats.average, 2)}` },
                { label: `Min: ${formatCurrency(data.stats.min, 2)}` },
                { label: `Max: ${formatCurrency(data.stats.max, 2)}` },
                data.stats.missingPoints > 0
                    ? { label: `Faltan ${data.stats.missingPoints} puntos`, type: 'warning' }
                    : { label: 'Sin huecos de carga', type: 'success' },
            ],
        });

        state.currentChartRows = buildChartRows(data.labels, data.prices);
        await loadDashboardSummary(date);
    }

    async function loadMonthChart(date) {
        const [year, month] = date.split('-');
        const data = await postForm('ajax/get_precios_por_mes.php', {
            mes: month,
            anio: year,
            market_type: state.marketType,
        });

        renderChart({
            type: 'line',
            labels: data.dias,
            datasets: [{
                label: `Precio medio diario ${month}/${year}`,
                data: data.preciosMedios.map((value) => toMWh(value)),
                borderColor: 'rgba(10, 132, 255, 1)',
                backgroundColor: 'rgba(10, 132, 255, 0.14)',
                borderWidth: 3,
                tension: 0.25,
                spanGaps: false,
                fill: true,
            }],
            title: `Media diaria del mes ${month}/${year}`,
            subtitle: 'Promedio de cada dia a partir de vw_OMIE_PRE_24',
            meta: [
                data.esParcial
                    ? { label: `Mes parcial · faltan ${data.diasFaltantes.length} dias`, type: 'warning' }
                    : { label: 'Mes completo', type: 'success' },
                { label: `Dias con huecos horarios: ${data.diasConHuecos.length}` },
            ],
        });

        state.currentChartRows = buildChartRows(data.dias, data.preciosMedios);
        await loadDashboardSummary(date);
    }

    async function loadYearChart(date) {
        const [year] = date.split('-');
        const data = await postForm('ajax/get_precios_por_anio.php', {
            anio: year,
            market_type: state.marketType,
        });

        const monthLabels = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'];

        renderChart({
            type: 'bar',
            labels: monthLabels,
            datasets: [{
                label: `Media mensual ${year}`,
                data: data.preciosMensuales.map((value) => toMWh(value)),
                borderColor: 'rgba(30, 157, 99, 1)',
                backgroundColor: 'rgba(30, 157, 99, 0.2)',
                borderWidth: 1,
            }],
            title: `Media mensual del ano ${year}`,
            subtitle: 'Promedio mensual calculado sobre medias diarias validas',
            meta: [
                { label: `Media anual: ${formatCurrency(data.mediaAnual, 2)}` },
                data.esParcial
                    ? { label: `Meses faltantes: ${data.mesesFaltantes.join(', ') || 'ninguno'}`, type: 'warning' }
                    : { label: 'Ano completo', type: 'success' },
            ],
        });

        state.currentChartRows = buildChartRows(monthLabels, data.preciosMensuales);
        await loadDashboardSummary(date);
    }

    async function refreshActiveChart() {
        const date = els.fechaSelect.value || today;

        try {
            if (state.mode === 'day') {
                await loadDayChart(date);
            } else if (state.mode === 'month') {
                await loadMonthChart(date);
            } else {
                await loadYearChart(date);
            }
        } catch (error) {
            showNoDataState(error.message);
        }
    }

    function showDetailHtml(html) {
        els.detalle.innerHTML = html;
        els.detalle.classList.remove('detail-empty');
        revealDetailSection(true);
    }

    function renderSolarDetail(data, date) {
        const rows = data.horas
            .map((hora, index) => `
                <tr>
                    <td>${formatDateDisplay(date)}</td>
                    <td>${hora}</td>
                    <td>${formatCurrency(data.precios[index], 2)}</td>
                </tr>
            `)
            .join('');

        const html = `
            <div class="table-responsive">
                <table class="table table-striped table-hover align-middle">
                    <thead>
                        <tr>
                            <th>Fecha</th>
                            <th>Hora</th>
                            <th>Precio solar</th>
                        </tr>
                    </thead>
                    <tbody>${rows}</tbody>
                </table>
            </div>
        `;

        showDetailHtml(html);
    }

    async function applyFilter() {
        const fechaInicio = els.fechaInicio.value;
        const fechaFin = els.fechaFin.value;
        const tipo = els.tipoConsulta.value;

        const routes = {
            precio_medio: 'ajax/get_precio_medio.php',
            precio_solar: 'ajax/get_precio_solar.php',
            precio_tarifa: 'ajax/get_precio_tarifa.php',
            consumo_tarifa: 'ajax/get_consumo_tarifa.php',
        };

        const url = routes[tipo];
        if (!url) {
            return;
        }

        const html = await postForm(url, {
            fecha_inicio: fechaInicio,
            fecha_fin: fechaFin,
        }, 'text');

        els.resultados.innerHTML = html;
        els.exportTable.classList.remove('d-none');
        paginateResultsTable();
        await loadAlerts();
    }

    els.filtrar.addEventListener('click', async () => {
        try {
            await applyFilter();
        } catch (error) {
            els.resultados.innerHTML = `<div class="alert alert-danger mb-0">${error.message}</div>`;
        }
    });

    els.reset.addEventListener('click', async () => {
        els.fechaInicio.value = today.slice(0, 8) + '01';
        els.fechaFin.value = today;
        els.fechaSelect.value = today;
        els.tipoConsulta.value = 'precio_medio';
        state.mode = 'day';
        state.resolution = '24';
        setSegmentedState(els.mostrarDia, [els.mostrarDia, els.mostrarMes, els.mostrarAnio]);
        setSegmentedState(els.resolution24, [els.resolution24, els.resolution96]);
        els.resultados.innerHTML = `
            <div class="empty-state">
                <i class="bi bi-graph-up-arrow"></i>
                <p class="mb-0">Aplica un filtro para cargar una tabla comparativa.</p>
            </div>
        `;
        clearResultsPagination();
        els.exportTable.classList.add('d-none');
        els.detalle.innerHTML = 'Selecciona una fecha de la tabla para ver el detalle horario.';
        els.detalle.classList.add('detail-empty');
        els.toggleDetalle.classList.add('d-none');
        els.detailSection.classList.add('d-none');
        await Promise.all([refreshActiveChart(), loadAlerts()]);
    });

    els.mostrarDia.addEventListener('click', async () => {
        state.mode = 'day';
        setSegmentedState(els.mostrarDia, [els.mostrarDia, els.mostrarMes, els.mostrarAnio]);
        await refreshActiveChart();
    });

    els.mostrarMes.addEventListener('click', async () => {
        state.mode = 'month';
        setSegmentedState(els.mostrarMes, [els.mostrarDia, els.mostrarMes, els.mostrarAnio]);
        await refreshActiveChart();
    });

    els.mostrarAnio.addEventListener('click', async () => {
        state.mode = 'year';
        setSegmentedState(els.mostrarAnio, [els.mostrarDia, els.mostrarMes, els.mostrarAnio]);
        await refreshActiveChart();
    });

    els.resolution24.addEventListener('click', async () => {
        state.resolution = '24';
        setSegmentedState(els.resolution24, [els.resolution24, els.resolution96]);
        if (state.mode === 'day') {
            await refreshActiveChart();
        }
    });

    els.resolution96.addEventListener('click', async () => {
        state.resolution = '96';
        setSegmentedState(els.resolution96, [els.resolution24, els.resolution96]);
        if (state.mode === 'day') {
            await refreshActiveChart();
        }
    });

    els.fechaSelect.addEventListener('change', refreshActiveChart);
    els.refreshAlerts.addEventListener('click', loadAlerts);
    els.tipoConsulta.addEventListener('change', updateConsultaInfo);

    els.toggleDetalle.addEventListener('click', () => {
        if (els.detalle.style.display === 'none') {
            els.detalle.style.display = 'block';
            els.toggleDetalle.textContent = 'Ocultar detalle';
        } else {
            els.detalle.style.display = 'none';
            els.toggleDetalle.textContent = 'Mostrar detalle';
        }
    });

    els.resultados.addEventListener('click', async (event) => {
        const detailLink = event.target.closest('.detalle-dia');
        const solarLink = event.target.closest('.detalle-dia-solar');

        try {
            if (detailLink) {
                event.preventDefault();
                const date = detailLink.dataset.fecha;
                const html = await postForm('ajax/get_detalle_por_dia.php', { fecha: date }, 'text');
                showDetailHtml(html);
                els.fechaSelect.value = date;
                state.mode = 'day';
                setSegmentedState(els.mostrarDia, [els.mostrarDia, els.mostrarMes, els.mostrarAnio]);
                await refreshActiveChart();
            }

            if (solarLink) {
                event.preventDefault();
                const date = solarLink.dataset.fecha;
                const data = await postForm('ajax/get_detalle_solar.php', { fecha: date });
                renderSolarDetail(data, date);
            }
        } catch (error) {
            showDetailHtml(`<div class="alert alert-danger mb-0">${error.message}</div>`);
        }
    });

    els.exportChart.addEventListener('click', () => {
        if (!state.currentChartRows.length) {
            return;
        }

        const date = els.fechaSelect.value || today;
        downloadExcel(`omie_${state.mode}_${state.resolution}_${date}.xlsx`, state.currentChartRows, 'Grafica');
    });

    els.exportTable.addEventListener('click', () => {
        const table = els.resultados.querySelector('table');
        if (!table) {
            return;
        }

        const rows = Array.from(table.querySelectorAll('tr')).map((tr) =>
            Array.from(tr.querySelectorAll('th, td')).map((cell) => cell.textContent.trim())
        );
        downloadExcel(`omie_resultados_${els.fechaInicio.value || today}_${els.fechaFin.value || today}.xlsx`, rows, 'Resultados');
    });

    Promise.all([refreshActiveChart(), loadAlerts()]).catch((error) => {
        els.resultados.innerHTML = `<div class="alert alert-danger mb-0">${error.message}</div>`;
    });

    updateConsultaInfo();
});
