(() => {
    const state = {
        first: null,
        second: null,
        parseTimers: {}
    };

    document.addEventListener('DOMContentLoaded', () => {
        bindEvents();
        updateReference('first', null);
        updateReference('second', null);
        updateTimeLimits();
    });

    function bindEvents() {
        const first = el('tle-first-text');
        const second = el('tle-second-text');
        first?.addEventListener('input', () => scheduleParse('first'));
        second?.addEventListener('input', () => scheduleParse('second'));
        el('tle-comparison-time')?.addEventListener('change', validateCalculationTime);
        el('tle-compare-submit')?.addEventListener('click', compareTle);
        el('tle-compare-clear')?.addEventListener('click', clearPage);
    }

    function scheduleParse(side) {
        window.clearTimeout(state.parseTimers[side]);
        const text = getTleText(side);
        if (!text.trim()) {
            state[side] = null;
            updateReference(side, null);
            updateTimeLimits();
            return;
        }
        setStatus(side, 'Разбор...', 'text-muted');
        state.parseTimers[side] = window.setTimeout(() => parseTle(side), 350);
    }

    async function parseTle(side) {
        try {
            const parsed = await postJson('/api/tle-comparison/parse', { tle: getTleText(side) });
            state[side] = parsed;
            updateReference(side, parsed);
            updateTimeLimits();
            setStatus(side, 'Разобрано', 'tle-parse-ok');
        } catch (error) {
            state[side] = null;
            updateReference(side, null);
            updateTimeLimits();
            setStatus(side, error.message || 'Ошибка разбора', 'tle-parse-error');
        }
    }

    async function compareTle() {
        showAlert('');
        const first = getTleText('first');
        const second = getTleText('second');
        const time = getCalculationTime();
        if (!first.trim() || !second.trim()) {
            showAlert('Введите оба TLE для сравнения.', 'warning');
            return;
        }
        if (!time) {
            showAlert('Задайте время расчета.', 'warning');
            return;
        }
        const minTime = maxEpoch();
        const calculationDate = parseCalculationInput();
        const minDate = PcpUtcTime.parseApiDate(minTime);
        if (calculationDate && minDate && calculationDate.getTime() < minDate.getTime()) {
            showAlert(`Время расчета должно быть не раньше максимальной эпохи TLE: ${formatDateTime(minTime)}.`, 'warning');
            return;
        }

        setCompareLoading(true);
        try {
            const response = await postJson('/api/tle-comparison/compare', { first, second, time });
            renderComparison(response);
        } catch (error) {
            showAlert(error.message || 'Не удалось выполнить сравнение TLE.', 'danger');
        } finally {
            setCompareLoading(false);
        }
    }

    function renderComparison(response) {
        const rows = response?.rows || [];
        const body = el('tle-comparison-result-body');
        const empty = el('tle-comparison-empty');
        const wrap = el('tle-comparison-table-wrap');
        const meta = el('tle-comparison-result-meta');
        if (!body || !empty || !wrap) return;

        if (!rows.length) {
            body.innerHTML = '';
            empty.classList.remove('d-none');
            wrap.classList.add('d-none');
            if (meta) meta.textContent = 'Нет данных для сравнения.';
            return;
        }

        body.innerHTML = rows.map((row) => `
            <tr>
                <td>${escapeHtml(row.name || row.code || '')}</td>
                <td>${escapeHtml(emptyToDash(row.first))}</td>
                <td>${escapeHtml(emptyToDash(row.second))}</td>
                <td class="${deltaClass(row.delta)}">${escapeHtml(emptyToDash(row.delta))}</td>
            </tr>
        `).join('');

        empty.classList.add('d-none');
        wrap.classList.remove('d-none');
        if (meta) {
            const deltaNorm = response.radiusVectorDelta?.norm;
            const deltaText = Number.isFinite(deltaNorm) ? `${formatNumber(deltaNorm)} м` : '—';
            meta.textContent = `Время расчета: ${formatDateTime(response.time)}. |Δr| = ${deltaText}. Эпохи: TLE 1 — ${formatDateTime(response.firstEpoch)}, TLE 2 — ${formatDateTime(response.secondEpoch)}.`;
        }
    }

    function updateReference(side, parsed) {
        setText(`tle-${side}-epoch`, formatDateTime(parsed?.time) || '—');
        setText(`tle-${side}-norad`, parsed?.noradId ?? '—');
        setText(`tle-${side}-revolution`, parsed?.revolution ?? '—');
        if (!parsed) {
            const text = getTleText(side);
            setStatus(side, text.trim() ? 'Ошибка разбора' : 'Нет данных', text.trim() ? 'tle-parse-error' : 'text-muted');
        }
    }

    function updateTimeLimits() {
        const input = el('tle-comparison-time');
        const helper = el('tle-comparison-time-helper');
        const minTime = maxEpoch();
        if (!input) return;
        if (!minTime) {
            input.removeAttribute('min');
            if (helper) helper.textContent = 'Минимальное допустимое время появится после разбора двух TLE.';
            return;
        }
        input.min = toDateTimeLocalValue(minTime);
        if (!input.value || input.value < input.min) {
            input.value = input.min;
        }
        if (helper) helper.textContent = `Минимальное допустимое время: ${formatDateTime(minTime)}.`;
    }

    function validateCalculationTime() {
        const input = el('tle-comparison-time');
        const minTime = maxEpoch();
        if (!input || !minTime || !input.value) return;
        const time = parseCalculationInput();
        const minDate = PcpUtcTime.parseApiDate(minTime);
        if (time && minDate && time.getTime() < minDate.getTime()) {
            showAlert(`Время расчета должно быть не раньше максимальной эпохи TLE: ${formatDateTime(minTime)}.`, 'warning');
        }
    }

    function clearPage() {
        el('tle-first-text').value = '';
        el('tle-second-text').value = '';
        const time = el('tle-comparison-time');
        if (time) time.value = '';
        state.first = null;
        state.second = null;
        updateReference('first', null);
        updateReference('second', null);
        updateTimeLimits();
        showAlert('');
        renderComparison({ rows: [] });
        setText('tle-comparison-result-meta', 'Задайте время не раньше максимальной эпохи TLE и нажмите “Сравнить”.');
    }

    async function postJson(url, payload) {
        const response = await fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
        });
        if (!response.ok) {
            let message = `HTTP ${response.status}`;
            try {
                const error = await response.json();
                message = error.error || Object.values(error)[0] || message;
            } catch (_) {
                message = await response.text() || message;
            }
            throw new Error(message);
        }
        return response.json();
    }

    function maxEpoch() {
        const first = PcpUtcTime.parseApiDate(state.first?.time);
        const second = PcpUtcTime.parseApiDate(state.second?.time);
        if (!first || !second) return null;
        return first.getTime() >= second.getTime() ? state.first.time : state.second.time;
    }

    function parseCalculationInput() {
        const value = el('tle-comparison-time')?.value;
        return value ? new Date(value) : null;
    }

    function getCalculationTime() {
        const value = el('tle-comparison-time')?.value;
        return value ? PcpUtcTime.toUtcIsoFromInput(value) : null;
    }

    function getTleText(side) {
        return el(`tle-${side}-text`)?.value || '';
    }

    function setStatus(side, text, cssClass) {
        const node = el(`tle-${side}-status`);
        if (!node) return;
        node.className = `tle-parse-status ${cssClass || 'text-muted'}`;
        node.textContent = text;
    }

    function setCompareLoading(loading) {
        const button = el('tle-compare-submit');
        if (!button) return;
        button.disabled = loading;
        button.textContent = loading ? 'Расчет...' : 'Рассчитать';
    }

    function showAlert(message, type = 'info') {
        const container = el('tle-comparison-alert');
        if (!container) return;
        container.innerHTML = message
            ? `<div class="alert alert-${type} alert-dismissible fade show" role="alert">
                   ${escapeHtml(message)}
                   <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button>
               </div>`
            : '';
    }

    function toDateTimeLocalValue(value) {
        return PcpUtcTime.toLocalInputValue(value, true);
    }

    function formatDateTime(value) {
        return value ? PcpUtcTime.formatDateTime(value) : '';
    }

    function formatNumber(value) {
        return Number(value).toLocaleString('ru-RU', { maximumFractionDigits: 3 });
    }

    function emptyToDash(value) {
        return value === null || value === undefined || value === '' ? '—' : value;
    }

    function deltaClass(value) {
        const text = String(value || '').trim();
        if (text.startsWith('+')) return 'tle-delta-positive';
        if (text.startsWith('-')) return 'tle-delta-negative';
        return '';
    }

    function setText(id, value) {
        const node = el(id);
        if (node) node.textContent = value;
    }

    function escapeHtml(value) {
        return String(value ?? '')
            .replaceAll('&', '&amp;')
            .replaceAll('<', '&lt;')
            .replaceAll('>', '&gt;')
            .replaceAll('"', '&quot;')
            .replaceAll("'", '&#039;');
    }

    function el(id) {
        return document.getElementById(id);
    }
})();
