(function () {
    const pageRoot = document.getElementById('satellite-pdcm-page');
    if (!pageRoot) {
        return;
    }

    const apiBase = '/api/catalog/satellites/pdcm';
    const state = {
        satellites: [],
        selectedSatelliteId: null,
        details: null
    };
    const sendInitialConditionsDateTimePattern = /^(\d{2})\.(\d{2})\.(\d{4}) (\d{2}):(\d{2}):(\d{2})\.(\d{3})$/;

    function showAlert(message, type = 'danger') {
        const container = document.getElementById('satellite-pdcm-alert');
        if (!message) {
            container.innerHTML = '';
            return;
        }
        container.innerHTML = `<div class="alert alert-${type} mb-3" role="alert">${escapeHtml(message)}</div>`;
    }

    async function requestJson(url, options = {}) {
        const response = await fetch(url, {
            headers: {
                'Content-Type': 'application/json'
            },
            ...options
        });

        if (response.status === 204) {
            return null;
        }

        const isJson = response.headers.get('content-type')?.includes('application/json');
        const payload = isJson ? await response.json() : await response.text();

        if (!response.ok) {
            if (payload && typeof payload === 'object') {
                throw new Error(payload.error || Object.values(payload).join('; '));
            }
            throw new Error(payload || `HTTP ${response.status}`);
        }

        return payload;
    }

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

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

    function pad(value, length = 2) {
        return String(value).padStart(length, '0');
    }

    function currentDateTimeInputValue() {
        const now = new Date();
        return `${pad(now.getDate())}.${pad(now.getMonth() + 1)}.${now.getFullYear()} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`;
    }

    function formatDateTimeInput(value) {
        const date = PcpUtcTime.parseApiDate(value);
        if (!date) {
            return value || '';
        }
        return `${pad(date.getDate())}.${pad(date.getMonth() + 1)}.${date.getFullYear()} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}`;
    }

    function parseSendInitialConditionsTime() {
        const input = document.getElementById('satellite-pdcm-send-ic-time');
        const value = input?.value.trim() || '';
        const match = value.match(sendInitialConditionsDateTimePattern);
        if (!match) {
            return {
                valid: false,
                message: 'Введите время НУ в формате dd.mm.yyyy hh:MM:ss.zzz'
            };
        }

        const [, day, month, year, hour, minute, second, millisecond] = match;
        const parsed = new Date(
            Number(year),
            Number(month) - 1,
            Number(day),
            Number(hour),
            Number(minute),
            Number(second),
            Number(millisecond)
        );
        const validDate = parsed.getFullYear() === Number(year)
            && parsed.getMonth() === Number(month) - 1
            && parsed.getDate() === Number(day)
            && parsed.getHours() === Number(hour)
            && parsed.getMinutes() === Number(minute)
            && parsed.getSeconds() === Number(second)
            && parsed.getMilliseconds() === Number(millisecond);

        if (!validDate) {
            return {
                valid: false,
                message: 'Время НУ содержит некорректную дату или время'
            };
        }

        return {
            valid: true,
            text: value,
            iso: PcpUtcTime.toUtcIsoFromRussianDateTime(value)
        };
    }

    function parseDateTimeForPayload(value, fieldName) {
        const text = value?.trim() || '';
        const match = text.match(sendInitialConditionsDateTimePattern);
        if (!match) {
            throw new Error(`${fieldName}: укажите время в формате dd.mm.yyyy hh:MM:ss.zzz`);
        }

        const [, day, month, year, hour, minute, second, millisecond] = match;
        const parsed = new Date(
            Number(year),
            Number(month) - 1,
            Number(day),
            Number(hour),
            Number(minute),
            Number(second),
            Number(millisecond)
        );
        const validDate = parsed.getFullYear() === Number(year)
            && parsed.getMonth() === Number(month) - 1
            && parsed.getDate() === Number(day)
            && parsed.getHours() === Number(hour)
            && parsed.getMinutes() === Number(minute)
            && parsed.getSeconds() === Number(second)
            && parsed.getMilliseconds() === Number(millisecond);

        if (!validDate) {
            throw new Error(`${fieldName}: некорректная дата или время`);
        }

        return PcpUtcTime.toUtcIsoFromRussianDateTime(text);
    }

    function parseRequiredNumber(inputId, fieldName) {
        const value = document.getElementById(inputId)?.value;
        const number = Number(value);
        if (value === '' || !Number.isFinite(number)) {
            throw new Error(`${fieldName}: укажите число`);
        }
        return number;
    }

    function parseRequiredInteger(inputId, fieldName) {
        const number = parseRequiredNumber(inputId, fieldName);
        if (!Number.isInteger(number)) {
            throw new Error(`${fieldName}: укажите целое число`);
        }
        return number;
    }

    function formatNumber(value) {
        return Number(value ?? 0).toFixed(3);
    }

    function formatNullableNumber(value) {
        return value == null ? '-' : formatNumber(value);
    }

    function renderExportState(details) {
        const exportButton = document.getElementById('satellite-pdcm-export');
        exportButton.disabled = !details || !details.ascNodes || !details.ascNodes.length;
    }

    function renderSendInitialConditionsState(details, loading = false) {
        const button = document.getElementById('satellite-pdcm-send-ic');
        if (!button) {
            return;
        }

        const time = parseSendInitialConditionsTime();
        const enabled = !!details && time.valid && !loading;
        button.disabled = !enabled;
        button.textContent = loading ? 'Передача...' : 'Передать НУ в slot-service';
        if (!details) {
            button.title = 'Выберите спутник';
        } else if (!time.valid) {
            button.title = time.message;
        } else {
            button.title = '';
        }
    }

    function renderSetInitialConditionsState(details, loading = false) {
        const openButton = document.getElementById('satellite-pdcm-open-set-ic');
        const submitButton = document.getElementById('satellite-pdcm-set-ic-submit');
        const satelliteSelected = !!state.selectedSatelliteId;
        if (openButton) {
            openButton.disabled = !satelliteSelected || loading;
            openButton.title = satelliteSelected ? '' : 'Выберите спутник';
        }
        if (submitButton) {
            submitButton.disabled = loading;
            submitButton.textContent = loading ? 'Запуск...' : 'Запустить расчет';
        }
    }

    function renderList() {
        const tableBody = document.getElementById('satellite-pdcm-list');
        tableBody.innerHTML = '';

        if (!state.satellites.length) {
            tableBody.innerHTML = '<tr><td colspan="2" class="text-center text-muted py-4">Спутники не найдены</td></tr>';
            return;
        }

        state.satellites.forEach(satellite => {
            const tr = document.createElement('tr');
            if (satellite.satelliteId === state.selectedSatelliteId) {
                tr.classList.add('table-active');
            }
            const interval = satellite.availableInterval
                ? `
                    <span class="satellite-pdcm-interval-line">${escapeHtml(formatDateTimeLabel(satellite.availableInterval.timeStart))}</span>
                    <span class="satellite-pdcm-interval-line">${escapeHtml(formatDateTimeLabel(satellite.availableInterval.timeStop))}</span>
                `
                : 'Нет ПДЦМ';
            tr.innerHTML = `
                <td>
                    <div class="fw-semibold satellite-pdcm-satellite-name">
                        <span class="satellite-pdcm-status ${satellite.activeInterval ? 'satellite-pdcm-status-active' : 'satellite-pdcm-status-inactive'}"></span>
                        ${escapeHtml(satellite.name)}
                    </div>
                </td>
                <td class="satellite-pdcm-interval-cell">${interval}</td>
            `;
            tr.addEventListener('click', () => selectSatellite(satellite.satelliteId));
            tableBody.appendChild(tr);
        });
    }

    function renderSummary(details) {
        const summary = document.getElementById('satellite-pdcm-summary');
        if (!details) {
            summary.innerHTML = '<div class="catalog-helper">Выберите спутник слева.</div>';
            renderExportState(null);
            renderSendInitialConditionsState(null);
            renderSetInitialConditionsState(null);
            return;
        }

        const interval = details.availableInterval
            ? `${formatDateTimeLabel(details.availableInterval.timeStart)} - ${formatDateTimeLabel(details.availableInterval.timeStop)}`
            : 'Нет доступного интервала';
        const status = details.activeInterval ? 'Активен сейчас' : 'Неактивен сейчас';

        summary.innerHTML = `
            <div class="satellite-pdcm-summary-grid">
                <div class="satellite-pdcm-summary-card">
                    <div class="satellite-pdcm-summary-label">Спутник</div>
                    <div class="satellite-pdcm-summary-value">${escapeHtml(details.name)}</div>
                    <div class="catalog-helper">${escapeHtml(details.code || String(details.satelliteId))} · ID ${details.satelliteId}</div>
                </div>
                <div class="satellite-pdcm-summary-card">
                    <div class="satellite-pdcm-summary-label">Статус</div>
                    <div class="satellite-pdcm-summary-value">${escapeHtml(status)}</div>
                </div>
                <div class="satellite-pdcm-summary-card">
                    <div class="satellite-pdcm-summary-label">Интервал ПДЦМ</div>
                    <div class="satellite-pdcm-summary-value">${escapeHtml(interval)}</div>
                </div>
                <div class="satellite-pdcm-summary-card">
                    <div class="satellite-pdcm-summary-label">Записей asc-node</div>
                    <div class="satellite-pdcm-summary-value">${details.ascNodes.length}</div>
                </div>
            </div>
        `;
        renderExportState(details);
        renderSendInitialConditionsState(details);
        renderSetInitialConditionsState(details);
    }

    function renderTable(details) {
        const empty = document.getElementById('satellite-pdcm-table-empty');
        const wrap = document.getElementById('satellite-pdcm-table-wrap');

        if (!details || !details.availableInterval || !details.ascNodes.length) {
            empty.classList.remove('d-none');
            wrap.classList.add('d-none');
            wrap.innerHTML = '';
            renderExportState(details);
            return;
        }

        const rows = details.ascNodes.map(item => `
            <tr>
                <td>${escapeHtml(formatDateTimeLabel(item.time))}</td>
                <td>${item.revolution}</td>
                <td>${formatNumber(item.long)}</td>
                <td>${formatNumber(item.height)}</td>
                <td>${escapeHtml(formatDateTimeLabel(item.localMeanTime))}</td>
                <td>${formatNullableNumber(item.keps?.ael)}</td>
                <td>${formatNullableNumber(item.keps?.e)}</td>
                <td>${formatNullableNumber(item.keps?.inkl)}</td>
                <td>${formatNullableNumber(item.keps?.omega)}</td>
                <td>${formatNullableNumber(item.keps?.w)}</td>
                <td>${formatNumber(item.x)}</td>
                <td>${formatNumber(item.y)}</td>
                <td>${formatNumber(item.z)}</td>
                <td>${formatNumber(item.vx)}</td>
                <td>${formatNumber(item.vy)}</td>
                <td>${formatNumber(item.vz)}</td>
            </tr>
        `).join('');

        wrap.innerHTML = `
            <table class="table table-bordered align-middle satellite-pdcm-table mb-0">
                <thead>
                <tr>
                    <th>Время</th>
                    <th>Виток</th>
                    <th>Долгота</th>
                    <th>Высота</th>
                    <th>Местное ср. время</th>
                    <th>a</th>
                    <th>e</th>
                    <th>i</th>
                    <th>&Omega;</th>
                    <th>&omega;</th>
                    <th>X</th>
                    <th>Y</th>
                    <th>Z</th>
                    <th>Vx</th>
                    <th>Vy</th>
                    <th>Vz</th>
                </tr>
                </thead>
                <tbody>${rows}</tbody>
            </table>
        `;
        empty.classList.add('d-none');
        wrap.classList.remove('d-none');
        renderExportState(details);
    }

    function buildCsvValue(value) {
        const text = String(value ?? '');
        return `"${text.replaceAll('"', '""')}"`;
    }

    function exportCurrentCsv() {
        if (!state.details || !state.details.ascNodes.length) {
            return;
        }

        const rows = [
            [
                'Время',
                'Виток',
                'Долгота',
                'Высота',
                'Местное ср. время',
                'a',
                'e',
                'i',
                'Omega',
                'omega',
                'X',
                'Y',
                'Z',
                'Vx',
                'Vy',
                'Vz'
            ],
            ...state.details.ascNodes.map(item => [
                formatDateTimeLabel(item.time),
                item.revolution,
                formatNumber(item.long),
                formatNumber(item.height),
                formatDateTimeLabel(item.localMeanTime),
                item.keps?.ael ?? '',
                item.keps?.e ?? '',
                item.keps?.inkl ?? '',
                item.keps?.omega ?? '',
                item.keps?.w ?? '',
                formatNumber(item.x),
                formatNumber(item.y),
                formatNumber(item.z),
                formatNumber(item.vx),
                formatNumber(item.vy),
                formatNumber(item.vz)
            ])
        ];

        const csv = rows
            .map(row => row.map(buildCsvValue).join(';'))
            .join('\n');

        const fileName = `asc-node-${(state.details.code || state.details.satelliteId)}.csv`;
        const blob = new Blob([`\uFEFF${csv}`], {type: 'text/csv;charset=utf-8;'});
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = fileName;
        document.body.appendChild(link);
        link.click();
        link.remove();
        URL.revokeObjectURL(url);
    }

    async function sendInitialConditions() {
        if (!state.selectedSatelliteId || !state.details) {
            showAlert('Выберите спутник для передачи начальных условий');
            return;
        }
        const time = parseSendInitialConditionsTime();
        if (!time.valid) {
            showAlert(time.message);
            return;
        }
        renderSendInitialConditionsState(state.details, true);
        showAlert('');
        try {
            await requestJson(`${apiBase}/${state.selectedSatelliteId}/send-ic?time=${encodeURIComponent(time.iso)}`, {method: 'POST'});
            showAlert('Начальные условия спутника переданы в slot-service', 'success');
        } catch (error) {
            showAlert(error.message || 'Не удалось передать начальные условия в slot-service');
        } finally {
            renderSendInitialConditionsState(state.details);
        }
    }

    function resetInitialConditionsForm() {
        document.getElementById('satellite-pdcm-ic-time').value = currentDateTimeInputValue();
        document.getElementById('satellite-pdcm-ic-revolution').value = '';
        document.getElementById('satellite-pdcm-ic-movement-model').value = 'FOTO';
        document.getElementById('satellite-pdcm-ic-s-ball').value = '0';
        document.getElementById('satellite-pdcm-ic-f81').value = '147.8';
        ['x', 'y', 'z', 'vx', 'vy', 'vz'].forEach(field => {
            document.getElementById(`satellite-pdcm-ic-${field}`).value = '';
        });
    }

    function fillInitialConditionsForm(initialConditions) {
        document.getElementById('satellite-pdcm-ic-time').value =
            formatDateTimeInput(initialConditions?.ic?.orbPoint?.time) || currentDateTimeInputValue();
        document.getElementById('satellite-pdcm-ic-revolution').value =
            initialConditions?.ic?.orbPoint?.revolution ?? '';
        document.getElementById('satellite-pdcm-ic-movement-model').value =
            initialConditions?.movementModel || 'FOTO';
        document.getElementById('satellite-pdcm-ic-s-ball').value =
            initialConditions?.ic?.sBall ?? '0';
        document.getElementById('satellite-pdcm-ic-f81').value =
            initialConditions?.ic?.f81 ?? '147.8';
        document.getElementById('satellite-pdcm-ic-x').value = initialConditions?.ic?.orbPoint?.x ?? '';
        document.getElementById('satellite-pdcm-ic-y').value = initialConditions?.ic?.orbPoint?.y ?? '';
        document.getElementById('satellite-pdcm-ic-z').value = initialConditions?.ic?.orbPoint?.z ?? '';
        document.getElementById('satellite-pdcm-ic-vx').value = initialConditions?.ic?.orbPoint?.vx ?? '';
        document.getElementById('satellite-pdcm-ic-vy').value = initialConditions?.ic?.orbPoint?.vy ?? '';
        document.getElementById('satellite-pdcm-ic-vz').value = initialConditions?.ic?.orbPoint?.vz ?? '';
    }

    async function openSetInitialConditionsModal() {
        if (!state.selectedSatelliteId) {
            showAlert('Выберите спутник для задания начальных условий');
            return;
        }

        const selectedSatellite = state.details?.satelliteId === state.selectedSatelliteId
            ? state.details
            : state.satellites.find(satellite => satellite.satelliteId === state.selectedSatelliteId);
        document.getElementById('satellite-pdcm-set-ic-target').textContent =
            selectedSatellite
                ? `${selectedSatellite.name} · ID ${selectedSatellite.satelliteId}`
                : `ID ${state.selectedSatelliteId}`;
        resetInitialConditionsForm();

        if (window.bootstrap) {
            window.bootstrap.Modal.getOrCreateInstance(document.getElementById('satellite-pdcm-set-ic-modal')).show();
        }

        try {
            const currentInitialConditions = await requestJson(`${apiBase}/${state.selectedSatelliteId}/initial-conditions`);
            if (currentInitialConditions) {
                fillInitialConditionsForm(currentInitialConditions);
            }
        } catch (error) {
            showAlert(error.message || 'Не удалось загрузить актуальные начальные условия');
        }
    }

    function buildInitialConditionsPayload() {
        const movementModel = document.getElementById('satellite-pdcm-ic-movement-model').value || 'FOTO';
        return {
            satelliteId: state.selectedSatelliteId,
            movementModel,
            ic: {
                orbPoint: {
                    time: parseDateTimeForPayload(document.getElementById('satellite-pdcm-ic-time').value, 'Time'),
                    revolution: parseRequiredInteger('satellite-pdcm-ic-revolution', 'Revolution'),
                    vx: parseRequiredNumber('satellite-pdcm-ic-vx', 'Vx'),
                    vy: parseRequiredNumber('satellite-pdcm-ic-vy', 'Vy'),
                    vz: parseRequiredNumber('satellite-pdcm-ic-vz', 'Vz'),
                    x: parseRequiredNumber('satellite-pdcm-ic-x', 'X'),
                    y: parseRequiredNumber('satellite-pdcm-ic-y', 'Y'),
                    z: parseRequiredNumber('satellite-pdcm-ic-z', 'Z')
                },
                sBall: parseRequiredNumber('satellite-pdcm-ic-s-ball', 'S-ball'),
                f81: parseRequiredNumber('satellite-pdcm-ic-f81', 'F81')
            }
        };
    }

    async function submitInitialConditions(event) {
        event.preventDefault();
        if (!state.selectedSatelliteId) {
            showAlert('Выберите спутник для задания начальных условий');
            return;
        }

        let payload;
        try {
            payload = buildInitialConditionsPayload();
        } catch (error) {
            showAlert(error.message || 'Проверьте параметры начальных условий');
            return;
        }

        renderSetInitialConditionsState(state.details, true);
        showAlert('');
        try {
            await requestJson(`${apiBase}/${state.selectedSatelliteId}/initial-conditions`, {
                method: 'POST',
                body: JSON.stringify(payload)
            });
            const modalElement = document.getElementById('satellite-pdcm-set-ic-modal');
            if (window.bootstrap && modalElement) {
                window.bootstrap.Modal.getOrCreateInstance(modalElement).hide();
            }
            showAlert('Расчет ПДЦМ по начальным условиям запущен', 'success');
        } catch (error) {
            showAlert(error.message || 'Не удалось запустить расчет ПДЦМ по начальным условиям');
        } finally {
            renderSetInitialConditionsState(state.details);
        }
    }

    async function selectSatellite(satelliteId) {
        state.selectedSatelliteId = satelliteId;
        state.details = null;
        renderList();
        renderSendInitialConditionsState(null);
        renderSetInitialConditionsState(null);
        showAlert('');

        try {
            state.details = await requestJson(`${apiBase}/${satelliteId}`);
            renderSummary(state.details);
            renderTable(state.details);
            renderList();
        } catch (error) {
            state.details = null;
            renderSummary(null);
            renderTable(null);
            renderSetInitialConditionsState(null);
            showAlert(error.message || 'Не удалось загрузить ПДЦМ спутника');
        }
    }

    async function loadSatellites() {
        showAlert('');
        try {
            state.satellites = await requestJson(apiBase);
            renderList();
            const nextSatelliteId = state.selectedSatelliteId
                ?? state.satellites.find(item => item.activeInterval)?.satelliteId
                ?? state.satellites[0]?.satelliteId;
            if (nextSatelliteId) {
                await selectSatellite(nextSatelliteId);
            } else {
                state.selectedSatelliteId = null;
                state.details = null;
                renderSummary(null);
                renderTable(null);
            }
        } catch (error) {
            state.satellites = [];
            state.selectedSatelliteId = null;
            state.details = null;
            renderList();
            renderSummary(null);
            renderTable(null);
            showAlert(error.message || 'Не удалось загрузить список спутников');
        }
    }

    document.getElementById('satellite-pdcm-refresh').addEventListener('click', () => {
        loadSatellites();
    });
    document.getElementById('satellite-pdcm-export').addEventListener('click', exportCurrentCsv);
    document.getElementById('satellite-pdcm-send-ic').addEventListener('click', sendInitialConditions);
    document.getElementById('satellite-pdcm-open-set-ic').addEventListener('click', openSetInitialConditionsModal);
    document.getElementById('satellite-pdcm-set-ic-form').addEventListener('submit', submitInitialConditions);
    const sendInitialConditionsTimeInput = document.getElementById('satellite-pdcm-send-ic-time');
    sendInitialConditionsTimeInput.value = currentDateTimeInputValue();
    sendInitialConditionsTimeInput.addEventListener('input', () => renderSendInitialConditionsState(state.details));

    loadSatellites();
})();
