<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.w3.org/1999/xhtml"
      layout:decorate="~{layouts/main-layout}">
<head>
    <meta charset='utf-8'>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport"
          content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <meta name="cesium-sandcastle-labels" content="Showcases">
    <title>Карта</title>

    <link href="webjars/cesium/1.107.2/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    <link th:href="@{/css/map.css}" rel="stylesheet">
    <!-- Иконки Bootstrap -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
    <!-- Bootstrap CSS для табов -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">

    <script src="webjars/cesium/1.107.2/Build/Cesium/Cesium.js"></script>
    <script type="text/javascript" src="requests_scripts.js"></script>
    <script type="text/javascript" src="cesium_scripts.js"></script>
    <script type="text/javascript" src="dynamic_plan_map_layers.js"></script>

    <style>
        @import url(webjars/cesium/1.107.2/Build/Cesium/Widgets/widgets.css);

        html, body {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        .nav-tabs {
            border-bottom: 1px solid #dee2e6;
            padding: 0 15px;
            margin-bottom: 0;
        }
        .nav-tabs .nav-link {
            border: none;
            color: #6c757d;
            font-weight: 500;
            padding: 0.75rem 0.5rem;
            margin: 0 5px;
        }
        .nav-tabs .nav-link.active {
            color: #0d6efd;
            background-color: transparent;
            border-bottom: 3px solid #0d6efd;
        }
        .nav-tabs .nav-link:hover:not(.active) {
            color: #495057;
        }
        .tab-content {
            flex: 1;
            overflow-y: auto;
            padding: 15px;
        }
        .tab-pane {
            height: 100%;
        }
        .table-container {
            height: calc(100% - 150px);
            overflow-y: auto;
        }
        #requests-pane .table-container {
            height: auto;
        }
        .selected-counter {
            margin-top: 10px;
            padding: 5px 0;
            border-top: 1px solid #dee2e6;
        }
        .sidebar-controls {
            margin-top: 15px;
            padding-top: 15px;
            border-top: 1px solid #dee2e6;
        }
        #table-satellites {
            table-layout: fixed;
            width: 100%;
        }
        #table-satellites th,
        #table-satellites td {
            vertical-align: middle;
            padding-left: 0.35rem;
            padding-right: 0.35rem;
        }
        #table-satellites th:nth-child(1),
        #table-satellites td:nth-child(1) {
            width: 5.5rem;
            white-space: nowrap;
        }
        #table-satellites th:nth-child(2),
        #table-satellites td:nth-child(2) {
            width: auto;
            max-width: 8rem;
        }
        #table-satellites td:nth-child(2) {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        #table-satellites th:nth-child(3),
        #table-satellites td:nth-child(3),
        #table-satellites th:nth-child(4),
        #table-satellites td:nth-child(4),
        #table-satellites th:nth-child(5),
        #table-satellites td:nth-child(5),
        #table-satellites th:nth-child(6),
        #table-satellites td:nth-child(6) {
            width: 3.2rem;
            text-align: center;
            white-space: nowrap;
        }
    </style>
</head>
<body>
<th:block layout:fragment="content">

    <div class="main-container">
        <!-- Боковая панель -->
        <div class="sidebar">
            <div class="sidebar-content">

                <div class="time-range-widget mb-3">
                    <h6><i class="bi bi-clock me-1"></i> Интервал времени</h6>
                    <div class="row g-2 align-items-end">
                        <div class="col-12 col-md-5">
                            <div class="time-input-group">
                                <label for="startTime" class="form-label">Начальное время</label>
                                <input type="datetime-local"
                                       class="form-control form-control-sm"
                                       id="startTime">
                            </div>
                        </div>
                        <div class="col-12 col-md-5">
                            <div class="time-input-group">
                                <label for="endTime" class="form-label">Конечное время</label>
                                <input type="datetime-local"
                                       class="form-control form-control-sm"
                                       id="endTime">
                            </div>
                        </div>
                        <div class="col-12 col-md-2 d-grid">
                            <button type="button"
                                    class="btn btn-outline-primary btn-sm"
                                    id="redrawSatellitePlansBtn"
                                    onclick="redrawSelectedSatellitePlans()">
                                <i class="bi bi-arrow-repeat"></i>
                            </button>
                        </div>
                    </div>
                </div>

                <!-- Навигационные табы -->
                <ul class="nav nav-tabs" id="layerTabs" role="tablist">
                    <li class="nav-item" role="presentation">
                        <button class="nav-link active" id="satellites-tab" data-bs-toggle="tab"
                                data-bs-target="#satellites-pane" type="button" role="tab"
                                aria-controls="satellites-pane" aria-selected="true">
                            <i class="bi bi-satellite me-1"></i> Спутники
                        </button>
                    </li>
                    <li class="nav-item" role="presentation">
                        <button class="nav-link" id="stations-tab" data-bs-toggle="tab"
                                data-bs-target="#stations-pane" type="button" role="tab"
                                aria-controls="stations-pane" aria-selected="false">
                            <i class="bi bi-building me-1"></i> Станции
                        </button>
                    </li>
                    <li class="nav-item" role="presentation">
                        <button class="nav-link" id="requests-tab" data-bs-toggle="tab"
                                data-bs-target="#requests-pane" type="button" role="tab"
                                aria-controls="requests-pane" aria-selected="false">
                            <i class="bi bi-list-check me-1"></i> Заявки
                        </button>
                    </li>
                </ul>

                <!-- Содержимое табов -->
                <div class="tab-content" id="layerTabsContent">
                    <!-- Таб Спутников -->
                    <div class="tab-pane fade show active" id="satellites-pane" role="tabpanel"
                         aria-labelledby="satellites-tab" tabindex="0">

                        <!-- Список спутников -->
                        <div class="table-container" id="requestsTableContainer">
                            <div class="table-responsive">
                                <table class="table table-sm table-hover mb-0" id="table-satellites">
                                    <thead class="table-light">
                                    <tr>
                                        <th scope="col">Идентификатор</th>
                                        <th scope="col">Название</th>
                                        <th scope="col">План</th>
                                        <th scope="col">Брони</th>
                                        <th scope="col">Слоты</th>
                                        <th scope="col">Орбита</th>
                                    </tr>
                                    </thead>
                                    <tbody id="satsTableBody">
                                    <tr th:unless="${satellites == null || #lists.isEmpty(satellites)}"
                                        th:each="req, itrStat: ${satellites}"
                                        style="cursor: pointer;"
                                        th:data-name="${req.name}"
                                        th:data-inoradid="${req.noradId}">
                                        <td>[[${req.noradId}]]</td>
                                        <td th:title="${req.name}">[[${req.name}]]</td>
                                        <td>
                                            <input th:name="sat"
                                                   th:value="${req.noradId}"
                                                   type="checkbox"
                                                   th:checked="false"
                                                   th:onchange="checkSat(this.checked, this.value);"
                                                   class="sat-checkbox sat-plan-checkbox"/>
                                        </td>
                                        <td>
                                            <input th:name="sat-bookings"
                                                   th:value="${req.noradId}"
                                                   type="checkbox"
                                                   th:checked="false"
                                                   th:onchange="checkSatBookings(this.checked, this.value);"
                                                   class="sat-checkbox sat-bookings-checkbox"/>
                                        </td>
                                        <td>
                                            <input th:name="sat-slots"
                                                   th:value="${req.noradId}"
                                                   type="checkbox"
                                                   th:checked="false"
                                                   th:onchange="checkSatSlots(this.checked, this.value);"
                                                   class="sat-checkbox sat-slots-checkbox"/>
                                        </td>
                                        <td>
                                            <input th:name="sat-orbit"
                                                   th:value="${req.noradId}"
                                                   type="checkbox"
                                                   th:checked="false"
                                                   th:onchange="checkOrbit(this.checked, this.value);"
                                                   class="sat-checkbox"/>
                                        </td>
                                    </tr>
                                    <tr th:if="${satellites == null || #lists.isEmpty(satellites)}">
                                        <td colspan="6" class="text-center text-muted py-5 no-requests">
                                            Нет доступных спутников
                                        </td>
                                    </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                        <div class="mt-2">
                            <label for="satRunId" class="form-label form-label-sm mb-1">Run ID</label>
                            <input type="number"
                                   min="1"
                                   step="1"
                                   class="form-control form-control-sm"
                                   id="satRunId"
                                   placeholder="null">
                        </div>
                        <!-- Элементы управления спутниками -->
                        <div class="stations-controls mb-3">
                            <div class="form-check form-switch mb-2">
                                <input class="form-check-input" type="checkbox" id="toggleOrbit" checked
                                       onchange="handleOrbits(this.checked)">
                                <label class="form-check-label" for="toggleOrbit">Показать орбиты</label>
                            </div>
                            <div class="form-check form-switch mb-2">
                                <input class="form-check-input" type="checkbox" id="toggleFL" checked
                                       onchange="handleFl(this.checked)">
                                <label class="form-check-label" for="toggleFL">Показать трассы полета</label>
                            </div>
                            <div class="form-check form-switch mb-2">
                                <input class="form-check-input" type="checkbox" id="toggleSwath" checked
                                       onchange="handleSw(this.checked)">
                                <label class="form-check-label" for="toggleSwath">Показать полосы обзора</label>
                            </div>

                        </div>
                    </div>

                    <!-- Таб Станций -->
                    <div class="tab-pane fade" id="stations-pane" role="tabpanel"
                         aria-labelledby="stations-tab" tabindex="0">
                        <!-- Элементы управления станциями -->
                        <div class="stations-controls mb-3">
                            <div class="form-check form-switch mb-2">
                                <input class="form-check-input" type="checkbox" id="toggleStations" checked>
                                <label class="form-check-label" for="toggleStations">Показать станции</label>
                            </div>
                            <div class="form-check form-switch mb-2">
                                <input class="form-check-input" type="checkbox" id="toggleCoverage">
                                <label class="form-check-label" for="toggleCoverage">Показать зоны покрытия</label>
                            </div>
                            <div class="mb-2">
                                <label for="stationOrbitHeightKm" class="form-label form-label-sm mb-1">Высота орбиты, км</label>
                                <input type="number"
                                       class="form-control form-control-sm"
                                       id="stationOrbitHeightKm"
                                       min="1"
                                       step="1"
                                       value="500"
                                       onchange="handleStationOrbitHeightChange()">
                            </div>
                            <select class="form-select form-select-sm mb-2">
                                <option selected>Все типы станций</option>
                                <option value="1">Наземные</option>
                                <option value="2">Мобильные</option>
                                <option value="3">Контрольные</option>
                            </select>
                        </div>

                        <!-- Список станций -->
                        <div class="table-container">
                            <div class="table-responsive">
                                <table class="table table-sm table-hover mb-0" id="table-stations">
                                    <thead class="table-light">
                                    <tr>
                                        <th scope="col" style="width: 40px;">
                                            <input type="checkbox" id="selectAllStations">
                                        </th>
                                        <th scope="col">Название</th>
                                        <th scope="col">Номер</th>
                                    </tr>
                                    </thead>
                                    <tbody id="stationsTableBody">
                                    <tr th:unless="${stations == null || #lists.isEmpty(stations)}"
                                        th:each="req, itrStat: ${stations}"
                                        style="cursor: pointer;"
                                        th:data-name="${req.name}"
                                        th:data-inoradid="${req.id}">
                                        <td>
                                            <input th:name="sat"
                                                   th:value="${req.id}"
                                                   type="checkbox"
                                                   th:checked="false"
                                                   th:onchange="checkStation(this.checked, this.value);"
                                                   class="sat-checkbox"/>
                                        </td>
                                        <td>[[${req.name}]]</td>
                                        <td>[[${req.number}]]</td>
                                    </tr>
                                    <tr th:if="${satellites == null || #lists.isEmpty(satellites)}">
                                        <td colspan="4" class="text-center text-muted py-5 no-requests">
                                            Нет доступных станций
                                        </td>
                                    </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>


                    <!-- Таб Заявок -->
                    <div class="tab-pane fade" id="requests-pane" role="tabpanel"
                         aria-labelledby="requests-tab" tabindex="0">
                        <!-- Элементы управления заявками -->
                        <div class="time-range-widget">
                            <h6><i class="bi bi-clock me-1"></i> Параметры покрытия</h6>
                            <div class="d-flex align-items-end gap-2 mb-2">
                                <div class="form-check form-switch mb-0 flex-grow-1">
                                    <input class="form-check-input" type="checkbox" id="toggleCalcCoverage" checked>
                                    <label class="form-check-label" for="toggleCalcCoverage">Расчет схемы покрытия</label>
                                </div>
                                <div style="min-width: 120px;">
                                    <label for="coverageSun" class="form-label form-label-sm mb-1">Солнце</label>
                                    <input type="number"
                                           class="form-control form-control-sm"
                                           id="coverageSun"
                                           min="-90"
                                           max="90"
                                           step="0.1"
                                           value="-90">
                                </div>
                            </div>
                            <select class="form-select form-select-sm mb-2" id="selectNode">
                                <option selected>Не учитывать признак ветви</option>
                                <option value="1">Восходящая</option>
                                <option value="2">Нисходящая</option>
                            </select>
                            <div class="coverage-satellites-widget mt-2">
                                <button class="btn btn-outline-secondary btn-sm w-100 d-flex justify-content-between align-items-center"
                                        type="button"
                                        data-bs-toggle="collapse"
                                        data-bs-target="#coverageSatellitesCollapse"
                                        aria-expanded="false"
                                        aria-controls="coverageSatellitesCollapse">
                                    <span>Спутники для покрытия</span>
                                    <i class="bi bi-chevron-down"></i>
                                </button>
                                <div class="collapse mt-2" id="coverageSatellitesCollapse">
                                    <div class="d-flex justify-content-between align-items-center mb-1">
                                        <label class="form-label mb-0">Выбор спутников</label>
                                        <div class="btn-group btn-group-sm" role="group" aria-label="Выбор спутников">
                                            <button type="button"
                                                    class="btn btn-outline-secondary"
                                                    onclick="toggleCoverageSatellites(true)">
                                                Все
                                            </button>
                                            <button type="button"
                                                    class="btn btn-outline-secondary"
                                                    onclick="toggleCoverageSatellites(false)">
                                                Сброс
                                            </button>
                                        </div>
                                    </div>
                                    <div class="coverage-satellites-list border rounded p-2">
                                        <div th:unless="${satellites == null || #lists.isEmpty(satellites)}"
                                             th:each="sat : ${satellites}"
                                             class="form-check">
                                            <input class="form-check-input coverage-sat-checkbox"
                                                   type="checkbox"
                                                   th:id="'coverage-sat-' + ${sat.noradId}"
                                                   th:value="${sat.noradId}">
                                            <label class="form-check-label"
                                                   th:for="'coverage-sat-' + ${sat.noradId}">
                                                [[${sat.name}]] ([[${sat.noradId}]])
                                            </label>
                                        </div>
                                        <div th:if="${satellites == null || #lists.isEmpty(satellites)}"
                                             class="text-muted small">
                                            Нет доступных спутников
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="row g-2 mt-2">
                                <div class="col-md-6">
                                    <label for="coverageSchemeRollStep" class="form-label form-label-sm mb-1">Шаг roll, град</label>
                                    <input type="number"
                                           class="form-control form-control-sm"
                                           id="coverageSchemeRollStep"
                                           min="0"
                                           step="0.1"
                                           value="5.0">
                                </div>
                                <div class="col-md-6">
                                    <label for="coverageSchemeMinOverlap" class="form-label form-label-sm mb-1">Мин. overlap</label>
                                    <input type="number"
                                           class="form-control form-control-sm"
                                           id="coverageSchemeMinOverlap"
                                           min="0"
                                           step="0.01"
                                           value="0.05">
                                </div>
                                <div class="col-md-6">
                                    <label for="coverageSchemeOrientationTolerance" class="form-label form-label-sm mb-1">Допуск ориентации, град</label>
                                    <input type="number"
                                           class="form-control form-control-sm"
                                           id="coverageSchemeOrientationTolerance"
                                           min="0"
                                           step="0.1"
                                           value="15.0">
                                </div>
                                <div class="col-md-6 d-flex flex-column justify-content-end">
                                    <div class="form-check form-switch">
                                        <input class="form-check-input" type="checkbox" id="coverageSchemeStrictContinuous" checked>
                                        <label class="form-check-label" for="coverageSchemeStrictContinuous">Строгая непрерывность</label>
                                    </div>
                                    <div class="form-check form-switch">
                                        <input class="form-check-input" type="checkbox" id="coverageSchemeAllowPartial">
                                        <label class="form-check-label" for="coverageSchemeAllowPartial">Разрешить частичное покрытие</label>
                                    </div>
                                    <div class="form-check form-switch">
                                        <input class="form-check-input" type="checkbox" id="coverageSchemeIncludeDebug" checked>
                                        <label class="form-check-label" for="coverageSchemeIncludeDebug">Debug info</label>
                                    </div>
                                </div>
                            </div>

                        </div>
                        <div class="requests-controls mb-3">
                            <!-- Кнопка добавления заявки -->
                            <button class="btn btn-success btn-sm mb-2 w-100"
                                    type="button"
                                    data-bs-toggle="modal"
                                    data-bs-target="#addRequestModal">
                                <i class="bi bi-plus-circle me-1"></i> Добавить заявку
                            </button>
                            <!-- Новое поле фильтрации -->
                            <div class="input-group input-group-sm mb-2">
                                <span class="input-group-text">
                                    <i class="bi bi-search"></i>
                                </span>
                                <input type="text"
                                       class="form-control"
                                       id="requestFilter"
                                       placeholder="Фильтр по названию заявки...">
                                <button class="btn btn-outline-secondary"
                                        type="button"
                                        id="clearFilterBtn"
                                        title="Очистить фильтр">
                                    <i class="bi bi-x-lg"></i>
                                </button>
                            </div>
                        </div>

                        <!-- Список заявок -->
                        <div class="table-container">
                            <div class="table-responsive">
                                <table class="table table-sm table-hover mb-0" id="table-request">
                                    <thead class="table-light">
                                    <tr>
                                        <th scope="col" style="width: 40px;">
                                            <input type="checkbox"
                                                   id="selectAllCheckbox"
                                                   onchange="toggleSelectAll(this.checked)">
                                        </th>
                                        <th scope="col" class="sortable" data-sort="name" onclick="sortTable('name')">
                                            Название
                                            <span class="sort-icon" id="sort-icon-name">
                                                <i class="bi bi-arrow-down-up"></i>
                                            </span>
                                        </th>
                                        <th scope="col" class="sortable" data-sort="importance"
                                            onclick="sortTable('importance')">
                                            Важность
                                            <span class="sort-icon" id="sort-icon-importance">
                                                <i class="bi bi-arrow-down-up"></i>
                                            </span>
                                        </th>
                                        <th scope="col" class="sortable" data-sort="square"
                                            onclick="sortTable('square')">
                                            Площодь
                                            <span class="sort-icon" id="sort-icon-square">
                                                <i class="bi bi-arrow-down-up"></i>
                                            </span>
                                        </th>
                                        <th scope="col">Найти</th>
                                        <th scope="col">Покрыть</th>

                                    </tr>
                                    </thead>
                                    <tbody id="requestsTableBody">
                                    <tr th:unless="${requests == null || #lists.isEmpty(requests)}"
                                        th:each="req, itrStat: ${requests}"
                                        style="cursor: pointer;"
                                        th:data-name="${req.name}"
                                        th:data-importance="${req.importance}"
                                        th:data-square="${req.square}">
                                        <td>
                                            <input th:name="request"
                                                   th:value="${req.requestId}"
                                                   type="checkbox"
                                                   th:checked="false"
                                                   th:onchange="checkReq(this.checked, this.value);"
                                                   class="request-checkbox"/>
                                        </td>
                                        <td>[[${req.name}]]</td>
                                        <td>
                                            <span class="badge"
                                                  th:classappend="${req.importance} ge 0.8 ? 'bg-danger' :
                                                                 (${req.importance} ge 0.5 ? 'bg-warning' : 'bg-info')">
                                                [[${#numbers.formatDecimal(req.importance, 1, 4)}]]
                                            </span>
                                        </td>
                                        <td>[[${#numbers.formatDecimal(req.square, 1, 2)}]]</td>

                                        <td>
                                            <button th:name="fly-to-request"
                                                    style="width: 30px; height: 20px"
                                                    th:value="${req.requestId}"
                                                    th:onclick="flyToReq(this.value);"
                                                    class="btn btn-sm btn-outline-primary"
                                                    title="Показать на карте">
                                                <i class="bi bi-geo-alt"></i>
                                            </button>
                                        </td>
                                        <td>
                                            <div class="d-flex align-items-center gap-2">
                                                <input th:name="cov-request"
                                                       th:value="${req.requestId}"
                                                       type="checkbox"
                                                       th:checked="false"
                                                       th:onchange="covToReq(this.checked, this.value);"
                                                       class="cov-checkbox"
                                                       title="Покрытие слотами"/>
                                                <input th:name="coverage-scheme-request"
                                                       th:value="${req.requestId}"
                                                       type="checkbox"
                                                       th:checked="false"
                                                       th:onchange="coverageSchemeToReq(this.checked, this.value);"
                                                       class="coverage-scheme-checkbox"
                                                       title="Схема покрытия"/>
                                            </div>
                                        </td>


                                    </tr>
                                    <tr th:if="${requests == null || #lists.isEmpty(requests)}">
                                        <td colspan="6" class="text-center text-muted py-5 no-requests">
                                            Нет доступных заявок
                                        </td>
                                    </tr>
                                    </tbody>
                                </table>
                            </div>

                            <!-- Счетчик выбранных элементов -->
                            <div class="selected-counter" th:if="${requests != null && !#lists.isEmpty(requests)}">
                                <small class="text-muted">
                                    Выбрано: <span id="selectedCount">0</span> из <span id="totalCount"
                                                                                        th:text="${#lists.size(requests)}">0</span>
                                </small>
                            </div>


                            <!-- Таблица слотов (изначально скрыта) -->
                            <div class="slots-container" id="slotsContainer" style="display: none; margin-top: 15px; padding-top: 15px; border-top: 1px solid #dee2e6;">
                                <div class="slots-header d-flex justify-content-between align-items-center mb-2">
                                    <h6 class="mb-0">
                                        <i class="bi bi-calendar-event me-1"></i>
                                        <span id="slotsTitle">Интервалы покрытия заявки</span>
                                    </h6>
                                    <div class="slots-actions">
                                        <button class="btn btn-sm btn-outline-success me-2"
                                                id="bookSlotsBtn"
                                                onclick="bookVisibleSlots(this)"
                                                title="Забронировать отображаемые на карте слоты">
                                            <i class="bi bi-check2-square me-1"></i>
                                        </button>
                                        <button class="btn btn-sm btn-outline-warning me-2"
                                                id="cancelBookingBtn"
                                                onclick="cancelRequestBooking(this)"
                                                title="Отменить бронирование по заявке">
                                            <i class="bi bi-x-octagon me-1"></i>
                                        </button>
                                        <button class="btn btn-sm btn-outline-secondary me-2"
                                                id="exportSlotsBtn"
                                                onclick="exportSlotsToCSV()"
                                                title="Экспортировать в CSV">
                                            <i class="bi bi-download me-1"></i>
                                        </button>
                                        <button class="btn btn-sm btn-outline-danger"
                                                id="clearSlotsBtn"
                                                onclick="clearSlotsTable()"
                                                title="Очистить таблицу">
                                            <i class="bi bi-x-lg"></i>
                                        </button>
                                    </div>
                                </div>

                                <div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
                                    <table class="table table-sm table-hover table-bordered mb-0" id="slotsTable">
                                        <thead class="table-light">
                                        <tr>
                                            <th id="slotsPrimaryHeader" scope="col" class="sortable-slot" data-sort="cycle" onclick="sortSlotsTable('cycle')">
                                                № слота
                                                <span class="sort-icon" id="sort-icon-cycle">
                                <i class="bi bi-arrow-down-up"></i>
                            </span>
                                            </th>
                                            <th scope="col" class="sortable-slot" data-sort="satellite" onclick="sortSlotsTable('satellite')">
                                                Спутник
                                                <span class="sort-icon" id="sort-icon-satellite">
                                <i class="bi bi-arrow-down-up"></i>
                            </span>
                                            </th>
                                            <th scope="col" class="sortable-slot" data-sort="tn" onclick="sortSlotsTable('tn')">
                                                Начало
                                                <span class="sort-icon" id="sort-icon-tn">
                                <i class="bi bi-arrow-down-up"></i>
                            </span>
                                            </th>
                                            <th id="slotsStateHeader" scope="col" class="sortable-slot" data-sort="state" onclick="sortSlotsTable('state')">
                                                Статус
                                                <span class="sort-icon" id="sort-icon-state">
                                <i class="bi bi-arrow-down-up"></i>
                            </span>
                                            </th>
                                            <th scope="col" class="sortable-slot" data-sort="duration" onclick="sortSlotsTable('duration')">
                                                Длительность
                                                <span class="sort-icon" id="sort-icon-duration">
                                <i class="bi bi-arrow-down-up"></i>
                            </span>
                                            </th>
                                            <th scope="col">Найти</th>
                                            <th scope="col" class="text-center">
                                                <div class="d-flex align-items-center justify-content-center gap-1">
                                                    <input type="checkbox" id="toggleAllSlotsVisibility"
                                                           class="form-check-input"
                                                           checked
                                                           onchange="toggleAllSlotsVisibility(this.checked)"
                                                           title="Отобразить/скрыть все слоты">
                                                    <span>В</span>
                                                </div>
                                            </th>
                                        </tr>
                                        </thead>
                                        <tbody id="slotsTableBody">
                                        <tr>
                                            <td colspan="7" class="text-center text-muted py-4">
                                                Выберите заявку и включите покрытие для отображения интервалов
                                            </td>
                                        </tr>
                                        </tbody>
                                    </table>
                                </div>

                                <div class="slots-summary mt-2 p-2 bg-light rounded">
                                    <div class="row">
                                        <div class="col-md-3">
                                            <small><strong>Всего интервалов:</strong> <span id="totalSlotsCount">0</span></small>
                                        </div>
                                        <div class="col-md-3">
                                            <small><strong>Общая длительность:</strong> <span id="totalDuration">0</span> мин</small>
                                        </div>
                                        <div class="col-md-3">
                                            <small><strong>Спутников задействовано:</strong> <span id="satellitesCount">0</span></small>
                                        </div>
                                        <div class="col-md-3">
                                            <small><strong>Период:</strong> <span id="coveragePeriod">-</span></small>
                                        </div>
                                    </div>
                                </div>
                            </div>

                        </div>
                        <div class="heatmap-toggle">
                            <div class="d-flex w-100 gap-2">
                                <button id="heatmapBtn" class="btn btn-outline-primary btn-sm flex-fill"
                                        onclick="toggleHeatmap()">
                                    Тепловая карта
                                </button>
                                <button id="complexPlanBtn"
                                        class="btn btn-outline-success btn-sm flex-fill"
                                        onclick="runComplexPlan()">
                                    Ком.План
                                </button>
                            </div>
                            <div class="d-flex justify-content-end mt-2">
                                <label class="switch">
                                <input type="checkbox" id="heatmapToggle"
                                       onchange="handleHeatmapToggle(this.checked)">
                                <span class="slider round"></span>
                                </label>
                            </div>
                        </div>
                        <!-- Поле ввода минимальной важности -->
                        <div class="heatmap-settings mt-2" id="heatmapSettings">
                            <div class="input-group input-group-sm">
                                    <span class="input-group-text">
                                        <i class="bi bi-filter"></i>
                                    </span>
                                <input type="number"
                                       class="form-control"
                                       id="minImportance"
                                       min="0"
                                       step="0.0001"
                                       value="0"
                                       placeholder="Мин. важность"
                                       title="Минимальная важность для отображения на тепловой карте">
                            </div>
                            <div class="form-text mt-1">
                                <small>Показывать на карте объекты с важностью ≥ указанного значения</small>
                            </div>
                            <div class="input-group input-group-sm mt-2">
                                <span class="input-group-text">Lat</span>
                                <input type="number"
                                       class="form-control"
                                       id="heatmapCountLat"
                                       min="1"
                                       step="1"
                                       placeholder="countLat"
                                       title="Количество ячеек по широте для объединения">
                                <span class="input-group-text">Long</span>
                                <input type="number"
                                       class="form-control"
                                       id="heatmapCountLong"
                                       min="1"
                                       step="1"
                                       placeholder="countLong"
                                       title="Количество ячеек по долготе для объединения">
                            </div>
                        </div>
                    </div>

                </div>

            </div>
        </div>

        <!-- Контейнер для карты -->
        <div class="cesium-container">
            <div id="cesiumContainer"></div>
            <!-- Индикатор режима рисования поверх карты -->
            <div id="drawingOverlay" style="display: none; position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 1000; background: rgba(0,0,0,0.7); color: white; padding: 10px 20px; border-radius: 8px; font-size: 14px;">
                <i class="bi bi-pencil me-2"></i>
                <span id="drawingOverlayText">Кликните на карту для добавления точек. Двойной клик для завершения.</span>
                <button type="button" id="cancelDrawingBtn" class="btn btn-sm btn-outline-light ms-3">
                    <i class="bi bi-x-lg"></i> Отмена
                </button>
            </div>
        </div>
    </div>

    <!-- Модальное окно для добавления заявки -->
    <div class="modal fade" id="addRequestModal" tabindex="-1" aria-labelledby="addRequestModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="addRequestModalLabel">
                        <i class="bi bi-plus-circle me-2"></i>Добавление заявки
                    </h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
                </div>
                <div class="modal-body">
                    <form id="addRequestForm">
                        <div class="row">
                            <div class="col-md-6 mb-3">
                                <label for="requestName" class="form-label">Название заявки</label>
                                <input type="text" class="form-control" id="requestName" required
                                       placeholder="Введите название заявки">
                            </div>
                            <div class="col-md-6 mb-3">
                                <label for="requestImportance" class="form-label">Важность</label>
                                <input type="number" class="form-control" id="requestImportance"
                                       min="0" max="1" step="0.01" value="0.5" required>
                                <div class="form-text">Значение от 0 до 1</div>
                            </div>
                        </div>
                        <div class="mb-3">
                            <label for="requestGeoType" class="form-label">Тип геометрии</label>
                            <select class="form-select" id="requestGeoType" required>
                                <option value="POLYGON" selected>Полигон</option>
                                <option value="POINT">Точка</option>
                            </select>
                        </div>
                        <div class="mb-3">
                            <label class="form-label">Контур заявки (WKT)</label>
                            <div class="d-flex gap-2 mb-2">
                                <button type="button" class="btn btn-outline-primary btn-sm" id="drawPolygonBtn">
                                    <i class="bi bi-pencil me-1"></i>Нарисовать на карте
                                </button>
                                <button type="button" class="btn btn-outline-secondary btn-sm" id="clearPolygonBtn">
                                    <i class="bi bi-trash me-1"></i>Очистить
                                </button>
                            </div>
                            <textarea class="form-control font-monospace" id="requestContour" rows="3"
                                      placeholder="POLYGON ((lon1 lat1, lon2 lat2, ...))" required></textarea>
                            <div class="form-text">
                                Контур в формате WKT. Нажмите "Нарисовать на карте", затем кликайте на карту для добавления точек.
                                Двойной клик завершит рисование и вернёт вас к форме.
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
                    <button type="button" class="btn btn-success" id="saveRequestBtn">
                        <i class="bi bi-check-lg me-1"></i>Сохранить заявку
                    </button>
                </div>
            </div>
        </div>
    </div>

    <script th:inline="javascript" id="cesium_sandcastle_script" charset="utf-8">
        // Ждем полной загрузки DOM
        document.addEventListener('DOMContentLoaded', function() {
            // Инициализируем карту после полной загрузки страницы
            initializeCesium();
            window.PcpDynamicPlanMapLayers?.initializeMap(window.viewer);

            // Инициализируем состояние тепловой карты
            window.heatmapActive = false;

            // Инициализируем сортировку
            initTableSorting();

            // Настраиваем высоту таблицы
            adjustTableHeight();

            initializeTimeRange();
        });

        // Переменные для сортировки
        let currentSort = {
            column: null,
            direction: 'asc' // 'asc' или 'desc'
        };

        let checkboxStates = new Map();

        // Инициализация сортировки
        function initTableSorting() {
            // Устанавливаем начальные иконки
            updateSortIcons(null, null);
        }

        // Функция для настройки высоты таблицы
        function adjustTableHeight() {
       try {
            const activeTabPane = document.querySelector('.tab-pane.active');
            if (!activeTabPane) {
                console.warn('Не найден активный tab-pane');
                return;
            }

            const tableContainer = activeTabPane.querySelector('.table-container');
            if (!tableContainer) {
                console.warn('Не найден table-container в активной вкладке');
                return;
            }

            const sidebarHeader = document.querySelector('.sidebar-header');
            const sidebarControls = activeTabPane.querySelector('.sidebar-controls');
            const selectedCounter = activeTabPane.querySelector('.selected-counter');

            if (!sidebarHeader) {
                console.warn('Не найден sidebar-header');
                return;
            }

            const isRequestsPane = activeTabPane.id === 'requests-pane';
            const slotsContainer = document.getElementById('slotsContainer');
            const slotsVisible = isRequestsPane
                && slotsContainer
                && slotsContainer.style.display !== 'none';

            if (isRequestsPane && !slotsVisible) {
                tableContainer.style.height = 'auto';
                tableContainer.style.maxHeight = 'none';
                tableContainer.style.overflowY = 'visible';
                return;
            }

            const headerHeight = sidebarHeader.offsetHeight || 60;
            const controlsHeight = sidebarControls ? sidebarControls.offsetHeight : 0;
            const counterHeight = selectedCounter ? selectedCounter.offsetHeight : 0;
            const margins = 30; // отступы

            const availableHeight = window.innerHeight - headerHeight - controlsHeight - counterHeight - margins;

            if (availableHeight > 100) {
                tableContainer.style.overflowY = 'auto';
                tableContainer.style.maxHeight = availableHeight + 'px';
            } else {
                console.warn('Недостаточно высоты для таблицы:', availableHeight);
            }
        } catch (error) {
            console.error('Ошибка в adjustTableHeight:', error);
        }
        }

        // Основная функция сортировки
       function sortTable(column) {


            const tbody = document.getElementById('requestsTableBody');
            const rows = Array.from(tbody.querySelectorAll('tr:not(.no-requests)'));

            // Проверяем, есть ли данные для сортировки
            if (!tbody || rows.length === 0) {
                console.log('Нет данных для сортировки');
                return;
            }

            // Определяем направление сортировки
            let direction = 'asc';

            // Если уже сортировали по этому столбцу, меняем направление на противоположное
            if (currentSort.column === column) {
                direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
            } else {
                // Если выбрали новый столбец, сбрасываем направление на asc
                direction = 'asc';
            }

            // Обновляем текущую сортировку
            currentSort.column = column;
            currentSort.direction = direction;

            // Обновляем иконки сортировки
            updateSortIcons(column, direction);

            // Сохраняем состояния чекбоксов перед сортировкой
            saveCheckboxStates();

            // Сортируем строки
            rows.sort((a, b) => {
                let aValue, bValue;

                try {
                    switch (column) {
                        case 'name':
                            aValue = a.getAttribute('data-name') || '';
                            bValue = b.getAttribute('data-name') || '';
                            return direction === 'asc'
                                ? (aValue || '').localeCompare(bValue || '')
                                : (bValue || '').localeCompare(aValue || '');

                        case 'importance':
                            aValue = parseFloat(a.getAttribute('data-importance')) || 0;
                            bValue = parseFloat(b.getAttribute('data-importance')) || 0;
                            return direction === 'asc'
                                ? aValue - bValue
                                : bValue - aValue;

                        case 'square':
                            aValue = parseFloat(a.getAttribute('data-square')) || 0;
                            bValue = parseFloat(b.getAttribute('data-square')) || 0;
                            return direction === 'asc'
                                ? aValue - bValue
                                : bValue - aValue;

                        default:
                            return 0;
                    }
                } catch (error) {
                    console.error('Ошибка при сортировке:', error);
                    return 0;
                }
            });

            // Перемещаем отсортированные строки в таблицу
            try {
                // Удаляем все строки
                while (tbody.firstChild) {
                    tbody.removeChild(tbody.firstChild);
                }

                // Добавляем отсортированные строки
                rows.forEach(row => {
                    tbody.appendChild(row);
                });

                // Восстанавливаем состояния чекбоксов
                restoreCheckboxStates();

                // Обновляем счетчик
                updateSelectedCount();
            } catch (error) {
                console.error('Ошибка при обновлении таблицы:', error);
            }
        setTimeout(() => {
            const filterInput = document.getElementById('requestFilter');
            if (filterInput) {
                filterRequests(filterInput.value);
            }
        }, 0);
       }

        // Обновление иконок сортировки
       function updateSortIcons(column, direction) {
            try {
                // Сбрасываем все иконки
                const allHeaders = document.querySelectorAll('.sortable');
                allHeaders.forEach(th => {
                    th.classList.remove('asc', 'desc');
                    const icon = th.querySelector('.sort-icon i');
                    if (icon) {
                        icon.className = 'bi bi-arrow-down-up';
                    }
                });

                // Устанавливаем активную иконку
                if (column) {
                    const activeHeader = document.querySelector(`.sortable[data-sort="${column}"]`);
                    if (activeHeader) {
                        activeHeader.classList.add(direction);
                        const icon = activeHeader.querySelector('.sort-icon i');
                        if (icon) {
                            // Устанавливаем соответствующую иконку в зависимости от направления
                            if (direction === 'asc') {
                                icon.className = 'bi bi-sort-down';
                            } else {
                                icon.className = 'bi bi-sort-up';
                            }
                        }
                    }
                }
            } catch (error) {
                console.error('Ошибка при обновлении иконок:', error);
            }
        }

        // Сброс сортировки
        function resetSorting() {
            try {
                // Сбрасываем состояние сортировки
                currentSort.column = null;
                currentSort.direction = 'asc';

                // Сбрасываем иконки
                updateSortIcons(null, null);

                // Восстанавливаем исходный порядок
                const tbody = document.getElementById('requestsTableBody');
                if (!tbody) return;

                const rows = Array.from(tbody.querySelectorAll('tr:not(.no-requests)'));
                if (rows.length === 0) return;

                // Сохраняем состояния
                saveCheckboxStates();

                // Сортируем по requestId (исходный порядок)
                rows.sort((a, b) => {
                    const aCheckbox = a.querySelector('.request-checkbox');
                    const bCheckbox = b.querySelector('.request-checkbox');
                    const aId = aCheckbox ? parseInt(aCheckbox.value) || 0 : 0;
                    const bId = bCheckbox ? parseInt(bCheckbox.value) || 0 : 0;
                    return aId - bId;
                });

                // Обновляем таблицу
                rows.forEach(row => tbody.appendChild(row));

                // Восстанавливаем состояния
                restoreCheckboxStates();
                updateSelectedCount();

            } catch (error) {
                console.error('Ошибка при сбросе сортировки:', error);
            }
        }

        // Сохранение состояний чекбоксов
        function saveCheckboxStates() {
            try {
                checkboxStates.clear();
                const checkboxes = document.querySelectorAll('.request-checkbox');
                checkboxes.forEach(checkbox => {
                    checkboxStates.set(checkbox.value, checkbox.checked);
                });
            } catch (error) {
                console.error('Ошибка при сохранении состояний:', error);
            }
        }

        // Восстановление состояний чекбоксов
        function restoreCheckboxStates() {
            try {
                const checkboxes = document.querySelectorAll('.request-checkbox');
                checkboxes.forEach(checkbox => {
                    if (checkboxStates.has(checkbox.value)) {
                        checkbox.checked = checkboxStates.get(checkbox.value);
                    }
                });
            } catch (error) {
                console.error('Ошибка при восстановлении состояний:', error);
            }
        }

        // Обновление основной функции selectAllRequests
        function selectAllRequests() {
            const checkboxes = document.querySelectorAll('.request-checkbox');
            checkboxes.forEach(checkbox => {
                checkbox.checked = true;
                // Вызываем обработчик для каждого чекбокса
                if (typeof checkReq === 'function') {
                    checkReq(true, checkbox.value);
                }
            });
            updateSelectedCount();
            saveCheckboxStates();
        }

        // Обновление основной функции deselectAllRequests
        function deselectAllRequests() {
            const checkboxes = document.querySelectorAll('.request-checkbox');
            checkboxes.forEach(checkbox => {
                checkbox.checked = false;
                // Вызываем обработчик для каждого чекбокса
                if (typeof checkReq === 'function') {
                    checkReq(false, checkbox.value);
                }
            });
            updateSelectedCount();
            saveCheckboxStates();
        }

        // Обновление основной функции toggleSelectAll
        function toggleSelectAll(isChecked) {
            const checkboxes = document.querySelectorAll('.request-checkbox');
            checkboxes.forEach(checkbox => {
                checkbox.checked = isChecked;
                // Вызываем обработчик для каждого чекбокса
                if (typeof checkReq === 'function') {
                    checkReq(isChecked, checkbox.value);
                }
            });
            updateSelectedCount();
            saveCheckboxStates();
        }

        // Функция для обновления счетчика выбранных элементов
        function updateSelectedCount() {
            const checkboxes = document.querySelectorAll('.request-checkbox:checked');
            const selectedCountElement = document.getElementById('selectedCount');
            const filterInput = document.getElementById('requestFilter');

            if (selectedCountElement) {
        // Если активен фильтр, считаем только видимые выбранные
        if (filterInput && filterInput.value.trim() !== '') {
            const visibleChecked = Array.from(checkboxes).filter(cb => {
                const row = cb.closest('tr');
                return row && row.style.display !== 'none';
            });
            selectedCountElement.textContent = visibleChecked.length;
        } else {
            // Стандартный подсчет
            selectedCountElement.textContent = checkboxes.length;
        }
    }

            // Обновляем чекбокс "Выбрать все"
            const allCheckboxes = document.querySelectorAll('.request-checkbox');
            const selectAllCheckbox = document.getElementById('selectAllCheckbox');
            if (allCheckboxes.length > 0) {
                const allChecked = Array.from(allCheckboxes).every(cb => cb.checked);
                const anyChecked = Array.from(allCheckboxes).some(cb => cb.checked);
                selectAllCheckbox.checked = allChecked;
                selectAllCheckbox.indeterminate = anyChecked && !allChecked;
            }
        }

        // Функция для переключения тепловой карты (кнопка)
        function toggleHeatmap() {
            var toggle = document.getElementById('heatmapToggle');
            var newState = !toggle.checked;
            toggle.checked = newState;
            handleHeatmapToggle(newState);
        }

        // Обработчик переключателя тепловой карты
        function handleHeatmapToggle(isChecked) {
            window.heatmapActive = isChecked;

            // Обновляем стиль кнопки
            var heatmapBtn = document.getElementById('heatmapBtn');
            if (isChecked) {
                heatmapBtn.classList.remove('btn-outline-primary');
                heatmapBtn.classList.add('btn-primary');
                heatmapBtn.textContent = 'Тепловая карта (вкл)';
            } else {
                heatmapBtn.classList.remove('btn-primary');
                heatmapBtn.classList.add('btn-outline-primary');
                heatmapBtn.textContent = 'Тепловая карта';
            }

            // Вызываем основную функцию для работы с тепловой картой
            mapVisibility(isChecked);
        }

        function flyToReq(id){
            let ds = 'req_'+id
            const dataSource = viewer.dataSources.getByName(ds)[0];
            if (!dataSource) {
                console.error('DataSource не найден:', dataSourceName);
                return;
            }
            console.log(ds)

            const entityId = 'request_'+id
            const entity = dataSource.entities.getById(entityId);
            if (entity)
            {
                console.log('fly')
                // Если entity имеет позицию
                viewer.flyTo(entity,
                {
                    duration: 2
                });
            }
        }


        // Преобразует локальное datetime-local браузера в UTC ISO для API
        function toISOString(datetimeLocal) {
            if (!datetimeLocal) {
                return null;
            }

            const date = new Date(datetimeLocal);
            if (Number.isNaN(date.getTime())) {
                throw new Error('Некорректный формат даты');
            }

            return date.toISOString();
        }



        function covToReq(show, req_id){

            // Сбрасываем чекбокс видимости всех слотов
            const toggleAllCheckbox = document.getElementById('toggleAllSlotsVisibility');
            if (toggleAllCheckbox) {
                toggleAllCheckbox.checked = true;
            }
            const reqs = [[${requests}]];
            const req = reqs.find(function(element) {
                return element.requestId == req_id;
            });
            if (req) {

                // if (req.square > 500000){
                //     alert("Плщадь заявки не должна привышать 500.000 км2")
                //     return
                // }

                const startInput = toISOString(document.getElementById('startTime').value);
                const endInput = toISOString(document.getElementById('endTime').value);
                const node = document.getElementById('selectNode').value;
                const cover = document.getElementById('toggleCalcCoverage').checked;
                const sunInput = document.getElementById('coverageSun');
                const sun = Number.parseFloat(sunInput.value);

                if (!Number.isFinite(sun) || sun < -90 || sun > 90) {
                    alert('Значение поля "Солнце" должно быть в диапазоне от -90 до 90');
                    sunInput.focus();
                    return;
                }

                const satellites = getSelectedCoverageSatellites();
                drawReqCov(show, req, startInput, endInput, node, cover, satellites, sun);
            }
        }

        function coverageSchemeToReq(show, req_id) {
            const reqs = [[${requests}]];
            const req = reqs.find(function(element) {
                return element.requestId == req_id;
            });
            if (!req) {
                return;
            }

            const startInput = toISOString(document.getElementById('startTime').value);
            const endInput = toISOString(document.getElementById('endTime').value);
            const satellites = getSelectedCoverageSatellites();

            if (show && satellites.length === 0) {
                alert('Для расчета схемы покрытия выберите хотя бы один спутник');
                document.querySelector(`input[name="coverage-scheme-request"][value="${req_id}"]`).checked = false;
                return;
            }

            const options = getCoverageSchemeRequestOptions();
            drawReqCoverageScheme(show, req, startInput, endInput, satellites, options);
        }

        function getSelectedCoverageSatellites() {
            return Array.from(document.querySelectorAll('.coverage-sat-checkbox:checked'))
                .map(checkbox => checkbox.value);
        }

        function getSelectedCoverageSatelliteNames() {
            return Array.from(document.querySelectorAll('.coverage-sat-checkbox:checked'))
                .map(checkbox => {
                    const label = document.querySelector(`label[for="${checkbox.id}"]`);
                    return label ? label.textContent.trim() : `SAT-${checkbox.value}`;
                });
        }

        function setComplexPlanButtonLoading(isLoading) {
            const button = document.getElementById('complexPlanBtn');
            if (!button) {
                return;
            }

            if (!button.dataset.defaultText) {
                button.dataset.defaultText = button.innerHTML;
            }

            button.disabled = isLoading;
            button.innerHTML = isLoading
                ? '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Ком.План'
                : button.dataset.defaultText;
        }

        function getComplexPlanInterval() {
            const startValue = document.getElementById('startTime').value;
            const endValue = document.getElementById('endTime').value;

            if (!startValue || !endValue) {
                alert('Укажите интервал расчета перед запуском комплексного плана');
                return null;
            }

            const startDate = new Date(startValue);
            const endDate = new Date(endValue);
            if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
                alert('Не удалось распознать интервал расчета');
                return null;
            }

            if (startDate >= endDate) {
                alert('Начало интервала расчета должно быть раньше окончания');
                return null;
            }

            return {
                intervalStart: toISOString(startValue),
                intervalEnd: toISOString(endValue)
            };
        }

        function getFirstNumericValue(payload, fieldNames) {
            for (const fieldName of fieldNames) {
                const rawValue = payload?.[fieldName];
                if (typeof rawValue === 'number' && Number.isFinite(rawValue)) {
                    return rawValue;
                }

                if (typeof rawValue === 'string' && rawValue.trim() !== '') {
                    const parsedValue = Number(rawValue);
                    if (Number.isFinite(parsedValue)) {
                        return parsedValue;
                    }
                }
            }

            return null;
        }

        function formatMillisecondsDuration(durationMs) {
            if (!Number.isFinite(durationMs) || durationMs < 0) {
                return 'н/д';
            }

            if (durationMs < 1000) {
                return `${Math.round(durationMs)} мс`;
            }

            const totalSeconds = Math.round(durationMs / 1000);
            const hours = Math.floor(totalSeconds / 3600);
            const minutes = Math.floor((totalSeconds % 3600) / 60);
            const seconds = totalSeconds % 60;
            const parts = [];

            if (hours > 0) {
                parts.push(`${hours} ч`);
            }
            if (minutes > 0) {
                parts.push(`${minutes} мин`);
            }
            if (seconds > 0 || parts.length === 0) {
                parts.push(`${seconds} сек`);
            }

            return parts.join(' ');
        }

        function formatSecondsDuration(durationSeconds) {
            if (!Number.isFinite(durationSeconds) || durationSeconds < 0) {
                return 'н/д';
            }

            return formatMillisecondsDuration(durationSeconds * 1000);
        }

        function extractApiErrorMessage(payload, fallbackStatus) {
            if (!payload) {
                return `HTTP ${fallbackStatus}`;
            }

            if (typeof payload === 'string' && payload.trim() !== '') {
                return payload;
            }

            if (payload.error) {
                return payload.error;
            }

            if (payload.message) {
                return payload.message;
            }

            const values = Object.values(payload).filter(value => typeof value === 'string' && value.trim() !== '');
            if (values.length > 0) {
                return values.join(', ');
            }

            return `HTTP ${fallbackStatus}`;
        }

        function getComplexPlanSatelliteNames(payload) {
            const satellites = [[${satellites}]];
            const responseSatelliteIds = Array.isArray(payload?.satelliteIds)
                ? payload.satelliteIds
                    .map(value => Number(value))
                    .filter(value => Number.isFinite(value))
                : [];

            if (responseSatelliteIds.length > 0) {
                return responseSatelliteIds.map(satelliteId => {
                    const satellite = satellites.find(item => item.noradId === satelliteId);
                    return satellite ? `${satellite.name} (${satellite.noradId})` : `SAT-${satelliteId}`;
                });
            }

            return getSelectedCoverageSatelliteNames();
        }

        function formatComplexPlanResultMessage(payload) {
            const routeCount = getFirstNumericValue(payload, [
                'routesCount',
                'routesTotal',
                'routeCount',
                'calculatedModesCount'
            ]);
            const satelliteNames = getComplexPlanSatelliteNames(payload);

            return [
                'Расчет комплексного плана завершен.',
                `Длительность расчета: ${formatMillisecondsDuration(getFirstNumericValue(payload, ['durationMs']))}.`,
                `Количество маршрутов: ${routeCount !== null ? routeCount : 'н/д'}.`,
                `Аппараты: ${satelliteNames.length > 0 ? satelliteNames.join(', ') : 'н/д'}.`
            ].join('\n');
        }

        async function runComplexPlan() {
            const interval = getComplexPlanInterval();
            if (!interval) {
                return;
            }

            const satelliteIds = getSelectedCoverageSatellites()
                .map(value => Number(value))
                .filter(value => Number.isFinite(value));

            if (satelliteIds.length === 0) {
                alert('Выберите хотя бы один спутник в секции "Спутники для покрытия" на вкладке "Заявки"');
                return;
            }

            setComplexPlanButtonLoading(true);

            try {
                const countLat = parseOptionalPositiveInt(document.getElementById('heatmapCountLat').value);
                const countLong = parseOptionalPositiveInt(document.getElementById('heatmapCountLong').value);
                const response = await fetch('/api/com-plan/process', {
                    method: 'POST',
                    headers: {
                        'Accept': 'application/json',
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        intervalStart: interval.intervalStart,
                        intervalEnd: interval.intervalEnd,
                        satelliteIds: satelliteIds,
                        countLat: countLat,
                        countLong: countLong
                    })
                });

                const payload = await response.json().catch(() => ({}));
                if (!response.ok) {
                    throw new Error(extractApiErrorMessage(payload, response.status));
                }

                alert(formatComplexPlanResultMessage(payload));
            } catch (error) {
                alert('Ошибка при запуске расчета комплексного плана: ' + error.message);
            } finally {
                setComplexPlanButtonLoading(false);
            }
        }

        function toggleCoverageSatellites(isChecked) {
            document.querySelectorAll('.coverage-sat-checkbox').forEach(checkbox => {
                checkbox.checked = isChecked;
            });
        }


        // Основная функция для управления видимостью тепловой карты
        function mapVisibility(isChecked) {
            if (window.viewer) {
                if (isChecked) {
                    // Включение тепловой карты
                    const input = document.getElementById('minImportance');
                    let value = parseFloat(input.value);
                    const countLat = parseOptionalPositiveInt(document.getElementById('heatmapCountLat').value);
                    const countLong = parseOptionalPositiveInt(document.getElementById('heatmapCountLong').value);
                    showHeatmap(value, countLat, countLong);
                } else {
                    // Выключение тепловой карты
                    hideHeatmap();
                }
            }
        }

        function parseOptionalPositiveInt(value) {
            const parsedValue = parseInt(value, 10);
            if (isNaN(parsedValue) || parsedValue <= 0) {
                return null;
            }
            return parsedValue;
        }

        // Функция для обработки запросов
        function checkReq(show, req_id) {
            const reqs = [[${requests}]];
            const req = reqs.find(function(element) {
                return element.requestId == req_id;
            });
            if (req) {
                drawReq(show, req);
            }
            updateSelectedCount();
        }

        // Функция для обработки запросов
        function checkSat(show, sat_id) {
            const sats = [[${satellites}]];
            const req = sats.find(function(element) {
                return element.noradId == sat_id;
            });
            if (req) {
                const startInput = toISOString(document.getElementById('startTime').value);
                const endInput = toISOString(document.getElementById('endTime').value);
                drawSat(show, req, startInput, endInput, satellitePlanRunId());
            }
        }

        function satellitePlanRunId() {
            const input = document.getElementById('satRunId');
            return input?.value?.trim() || null;
        }

        function checkSatBookings(show, sat_id) {
            const sats = [[${satellites}]];
            const req = sats.find(function(element) {
                return element.noradId == sat_id;
            });
            if (req) {
                const startInput = toISOString(document.getElementById('startTime').value);
                const endInput = toISOString(document.getElementById('endTime').value);
                drawSatelliteBookedSlots(show, req, startInput, endInput);
            }
        }

        function checkSatSlots(show, sat_id) {
            const sats = [[${satellites}]];
            const req = sats.find(function(element) {
                return element.noradId == sat_id;
            });
            if (req) {
                const startInput = toISOString(document.getElementById('startTime').value);
                const endInput = toISOString(document.getElementById('endTime').value);
                drawSatelliteSlots(show, req, startInput, endInput);
            }
        }

        function redrawSelectedSatellitePlans() {
            const sats = [[${satellites}]];
            const startInput = toISOString(document.getElementById('startTime').value);
            const endInput = toISOString(document.getElementById('endTime').value);
            const selectedPlanCheckboxes = Array.from(
                document.querySelectorAll('input[name="sat"].sat-plan-checkbox:checked')
            );

            selectedPlanCheckboxes.forEach(function(checkbox) {
                const req = sats.find(function(element) {
                    return element.noradId == checkbox.value;
                });
                if (req) {
                    const runId = satellitePlanRunId();
                    drawSat(false, req, startInput, endInput, runId);
                    drawSat(true, req, startInput, endInput, runId);
                }
            });

            const selectedBookingCheckboxes = Array.from(
                document.querySelectorAll('input[name="sat-bookings"].sat-bookings-checkbox:checked')
            );

            selectedBookingCheckboxes.forEach(function(checkbox) {
                const req = sats.find(function(element) {
                    return element.noradId == checkbox.value;
                });
                if (req) {
                    drawSatelliteBookedSlots(false, req, startInput, endInput);
                    drawSatelliteBookedSlots(true, req, startInput, endInput);
                }
            });

            const selectedSlotCheckboxes = Array.from(
                document.querySelectorAll('input[name="sat-slots"].sat-slots-checkbox:checked')
            );

            selectedSlotCheckboxes.forEach(function(checkbox) {
                const req = sats.find(function(element) {
                    return element.noradId == checkbox.value;
                });
                if (req) {
                    drawSatelliteSlots(false, req, startInput, endInput);
                    drawSatelliteSlots(true, req, startInput, endInput);
                }
            });

            const selectedOrbitCheckboxes = Array.from(
                document.querySelectorAll('input[name="sat-orbit"]:checked')
            );

            selectedOrbitCheckboxes.forEach(function(checkbox) {
                const req = sats.find(function(element) {
                    return element.noradId == checkbox.value;
                });
                if (req) {
                    drawOrbit(false, req, startInput, endInput);
                    drawOrbit(true, req, startInput, endInput);
                }
            });
        }


        function checkStation(show, st_id) {
            const sts = [[${stations}]];
            const req = sts.find(function(element) {
                return element.id == st_id;
            });
            if (req) {
                console.log('изменить видимость станции ' + req.id)
                drawSt(show, req);
            }
        }

        function handleStationOrbitHeightChange() {
            document.querySelectorAll('#stationsTableBody input[type="checkbox"]:checked').forEach(function(checkbox) {
                checkStation(false, checkbox.value);
                checkStation(true, checkbox.value);
            });
        }


        // Функция для обработки запросов
        function checkOrbit(show, sat_id) {
            const sats = [[${satellites}]];
            const req = sats.find(function(element) {
                return element.noradId == sat_id;
            });
            if (req) {
                const startInput = toISOString(document.getElementById('startTime').value);
                const endInput = toISOString(document.getElementById('endTime').value);
                drawOrbit(show, req, startInput, endInput);
            }
        }



        // Дополнительные вспомогательные функции
        function clearAllMarkers() {
            if (window.viewer) {
                window.viewer.entities.removeAll();
            }
        }

        function zoomToDefault() {
            if (window.viewer) {
                viewer.camera.setView({
                    destination: Cesium.Rectangle.fromDegrees(351, 72.6, 76.3, 31.4)
                });
            }
        }

        // Инициализация при загрузке
        document.addEventListener('DOMContentLoaded', function() {
            updateSelectedCount();
            saveCheckboxStates(); // Сохраняем начальные состояния
        });





        // Функция фильтрации заявок по названию
function filterRequests(filterValue) {
    const filter = filterValue.toLowerCase().trim();
    const tbody = document.getElementById('requestsTableBody');
    if (!tbody) return;

    const rows = Array.from(tbody.querySelectorAll('tr:not(.no-requests)'));
    let visibleCount = 0;
    let selectedVisibleCount = 0;

    rows.forEach(row => {
        const name = (row.getAttribute('data-name') || '').toLowerCase();
        const matches = name.includes(filter);

        if (matches) {
            row.style.display = '';
            visibleCount++;
            // Проверяем, выбрана ли видимая заявка
            const checkbox = row.querySelector('.request-checkbox');
            if (checkbox && checkbox.checked) {
                selectedVisibleCount++;
            }
        } else {
            row.style.display = 'none';
        }
    });

    // Обновляем счетчик с учетом фильтрации
    updateFilteredCount(visibleCount, selectedVisibleCount);

    // Обработка сообщения "Нет результатов"
    handleNoResultsMessage(tbody, rows.length, visibleCount);
}

// Обновление счетчика с учетом фильтрации
function updateFilteredCount(visibleCount, selectedVisibleCount) {
    const totalCountEl = document.getElementById('totalCount');
    const selectedCountEl = document.getElementById('selectedCount');
    const filterInput = document.getElementById('requestFilter');

    if (totalCountEl && selectedCountEl && filterInput) {
        const isFiltered = filterInput.value.trim() !== '';

        if (isFiltered) {
            // Формат: "Выбрано: X из Y (фильтр: Z видно)"
            totalCountEl.textContent = `${visibleCount} из ${totalCountEl.dataset.total || '0'}`;
            selectedCountEl.textContent = selectedVisibleCount;

            // Добавляем визуальный индикатор фильтрации
            totalCountEl.closest('.selected-counter').classList.add('filtered');
        } else {
            // Восстанавливаем обычный счетчик
            totalCountEl.textContent = totalCountEl.dataset.total || '0';
            updateSelectedCount(); // стандартное обновление
            totalCountEl.closest('.selected-counter').classList.remove('filtered');
        }
    }
}

// Управление сообщением "Нет результатов"
function handleNoResultsMessage(tbody, totalRows, visibleCount) {
    let noResultsRow = tbody.querySelector('.no-results-filter');

    // Создаем строку "Нет результатов" если её нет
    if (!noResultsRow && totalRows > 0) {
        noResultsRow = document.createElement('tr');
        noResultsRow.className = 'no-results-filter text-center text-muted py-3';
        noResultsRow.innerHTML = `<td colspan="6">Нет заявок, соответствующих фильтру</td>`;
        tbody.appendChild(noResultsRow);
    }

    // Показываем/скрываем сообщение
    if (noResultsRow) {
        noResultsRow.style.display = (visibleCount === 0 && totalRows > 0) ? '' : 'none';
    }

    // Скрываем оригинальное сообщение "Нет доступных заявок" при фильтрации
    const originalNoRequests = tbody.querySelector('.no-requests');
    if (originalNoRequests) {
        originalNoRequests.style.display = (totalRows === 0) ? '' : 'none';
    }
}

// Инициализация фильтрации при загрузке
document.addEventListener('DOMContentLoaded', function() {
    const filterInput = document.getElementById('requestFilter');
    const clearBtn = document.getElementById('clearFilterBtn');

    if (filterInput) {
        // Сохраняем общее количество для счетчика
        const totalCountEl = document.getElementById('totalCount');
        if (totalCountEl) {
            totalCountEl.dataset.total = totalCountEl.textContent;
        }

        // Обработчик ввода
        filterInput.addEventListener('input', function(e) {
            filterRequests(e.target.value);
        });

        // Обработчик очистки
        if (clearBtn) {
            clearBtn.addEventListener('click', function() {
                filterInput.value = '';
                filterRequests('');
            });
        }

        // Применяем фильтр при загрузке (на случай сохраненного значения)
        filterRequests(filterInput.value);
    }
});


function initializeTimeRange() {
    const now = new Date();

    // Текущее время
    const startTime = now;

    // Текущее время + 14 дней
    const endTime = new Date(now);
    endTime.setDate(endTime.getDate() + 14);

    // Форматируем даты для поля ввода datetime-local (формат: YYYY-MM-DDTHH:mm)
    const formatDateTimeLocal = (date) => {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');

        return `${year}-${month}-${day}T${hours}:${minutes}`;
    };

    // Устанавливаем значения в поля ввода
    const startTimeInput = document.getElementById('startTime');
    const endTimeInput = document.getElementById('endTime');

    if (startTimeInput && endTimeInput) {
        startTimeInput.value = formatDateTimeLocal(startTime);
        endTimeInput.value = formatDateTimeLocal(endTime);
    }
}


        // Обработчик изменения размера окна
        window.addEventListener('resize', adjustTableHeight);


        // ==================== Функции для рисования полигона и создания заявки ====================

        let drawingHandler = null;
        let drawnPoints = [];
        let drawnEntity = null;
        let isDrawing = false;

        // Функция для перевода градусов в радианы
        function toRadians(degrees) {
            return degrees * Math.PI / 180;
        }

        // Функция для перевода радианов в градусы
        function toDegrees(radians) {
            return radians * 180 / Math.PI;
        }

        // Преобразование координат Cesium в WKT формат
        function cartesianToWKT(positions) {
            if (!positions || positions.length < 3) {
                return '';
            }

            const coordinates = positions.map(pos => {
                const cartographic = Cesium.Cartographic.fromCartesian(pos);
                const lon = toDegrees(cartographic.longitude);
                const lat = toDegrees(cartographic.latitude);
                return `${lon.toFixed(6)} ${lat.toFixed(6)}`;
            });

            // Замыкаем полигон (первая точка = последняя точка)
            const firstCoord = coordinates[0];
            const wkt = `POLYGON ((${coordinates.join(', ')}, ${firstCoord}))`;
            return wkt;
        }


        // Начало рисования полигона
        function startDrawing() {
            if (!window.viewer) {
                console.error('Viewer не инициализирован');
                return;
            }

            // Очищаем предыдущее рисование
            stopDrawing();
            clearDrawing();

            isDrawing = true;
            drawnPoints = [];

            // Закрываем модальное окно
            const modal = bootstrap.Modal.getInstance(document.getElementById('addRequestModal'));
            if (modal) {
                modal.hide();
            }

            // Показываем оверлей поверх карты
            document.getElementById('drawingOverlay').style.display = 'block';
            updateDrawingOverlayText('Кликните на карту для добавления точек. Двойной клик для завершения.');

            // Изменяем курсор
            viewer.canvas.style.cursor = 'crosshair';

            // Создаем обработчик событий
            drawingHandler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);

            // Обработчик клика (добавление точки)
            drawingHandler.setInputAction(function(click) {
                const cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid);
                if (cartesian) {
                    drawnPoints.push(cartesian);
                    updateDrawnPolygon();
                    updateDrawingOverlayText('Добавлено точек: ' + drawnPoints.length + '. Двойной клик для завершения.');
                }
            }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

            // Обработчик двойного клика (завершение)
            drawingHandler.setInputAction(function(click) {
                if (drawnPoints.length >= 3) {
                    finishDrawing();
                } else {
                    updateDrawingOverlayText('Для полигона нужно минимум 3 точки. Продолжайте кликать.');
                }
            }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

            // Обработчик движения мыши (предпросмотр)
            drawingHandler.setInputAction(function(movement) {
                if (drawnPoints.length > 0) {
                    const cartesian = viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);
                    if (cartesian) {
                        updateDrawnPolygonPreview(cartesian);
                    }
                }
            }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
        }

        // Обновление текста в оверлее
        function updateDrawingOverlayText(text) {
            document.getElementById('drawingOverlayText').textContent = text;
        }

        // Обновление нарисованного полигона
        function updateDrawnPolygon() {
            if (drawnPoints.length < 2) return;

            // Удаляем предыдущую сущность
            if (drawnEntity) {
                viewer.entities.remove(drawnEntity);
            }

            // Создаем новую сущность
            drawnEntity = viewer.entities.add({
                name: 'drawing_polygon',
                polygon: {
                    hierarchy: new Cesium.PolygonHierarchy(drawnPoints),
                    material: Cesium.Color.GREEN.withAlpha(0.3),
                    outline: true,
                    outlineColor: Cesium.Color.GREEN,
                    outlineWidth: 2
                },
                polyline: {
                    positions: [...drawnPoints, drawnPoints[0]],
                    material: Cesium.Color.GREEN,
                    width: 2
                }
            });
        }

        // Предпросмотр полигона при движении мыши
        function updateDrawnPolygonPreview(currentPosition) {
            if (drawnPoints.length < 1) return;

            // Удаляем предыдущую сущность
            if (drawnEntity) {
                viewer.entities.remove(drawnEntity);
            }

            // Создаем с предпросмотром
            const previewPoints = [...drawnPoints, currentPosition];
            drawnEntity = viewer.entities.add({
                name: 'drawing_polygon_preview',
                polygon: {
                    hierarchy: new Cesium.PolygonHierarchy(previewPoints),
                    material: Cesium.Color.GREEN.withAlpha(0.2),
                    outline: true,
                    outlineColor: Cesium.Color.YELLOW,
                    outlineWidth: 2
                },
                polyline: {
                    positions: [...previewPoints, drawnPoints[0]],
                    material: Cesium.Color.YELLOW,
                    width: 2,
                    clampToGround: true
                }
            });
        }

        // Завершение рисования
        function finishDrawing() {
            if (drawnPoints.length < 3) {
                alert('Для создания полигона необходимо минимум 3 точки');
                return;
            }

            stopDrawing();

            // Преобразуем в WKT
            const wkt = cartesianToWKT(drawnPoints);
            document.getElementById('requestContour').value = wkt;

            // Скрываем оверлей
            document.getElementById('drawingOverlay').style.display = 'none';

            // Финальное отображение полигона
            if (drawnEntity) {
                viewer.entities.remove(drawnEntity);
            }
            drawnEntity = viewer.entities.add({
                name: 'final_polygon',
                polygon: {
                    hierarchy: new Cesium.PolygonHierarchy(drawnPoints),
                    material: Cesium.Color.GREEN.withAlpha(0.4),
                    outline: true,
                    outlineColor: Cesium.Color.DARKGREEN,
                    outlineWidth: 3
                }
            });

            // Открываем модальное окно с заполненными данными
            const modal = new bootstrap.Modal(document.getElementById('addRequestModal'));
            modal.show();
        }

        // Остановка рисования
        function stopDrawing() {
            isDrawing = false;

            if (drawingHandler) {
                drawingHandler.destroy();
                drawingHandler = null;
            }

            if (viewer && viewer.canvas) {
                viewer.canvas.style.cursor = 'default';
            }
        }

        // Отмена рисования
        function cancelDrawing() {
            stopDrawing();
            clearDrawing();
            document.getElementById('drawingOverlay').style.display = 'none';

            // Возвращаемся к модальному окну
            const modal = new bootstrap.Modal(document.getElementById('addRequestModal'));
            modal.show();
        }

        // Очистка рисования
        function clearDrawing() {
            stopDrawing();

            if (drawnEntity && viewer) {
                viewer.entities.remove(drawnEntity);
                drawnEntity = null;
            }

            drawnPoints = [];
            document.getElementById('requestContour').value = '';
        }

        // Сохранение заявки
        function saveRequest() {
            const name = document.getElementById('requestName').value.trim();
            const importance = parseFloat(document.getElementById('requestImportance').value);
            const geoType = document.getElementById('requestGeoType').value;
            const contour = document.getElementById('requestContour').value.trim();

            // Валидация
            if (!name) {
                alert('Введите название заявки');
                return;
            }

            if (isNaN(importance) || importance < 0 || importance > 1) {
                alert('Важность должна быть от 0 до 1');
                return;
            }

            if (!contour) {
                alert('Нарисуйте или введите контур заявки');
                return;
            }

            // Формируем данные заявки (requestId генерируется на сервере)
            const requestData = {
                name: name,
                importance: importance,
                geoType: geoType,
                contour: contour
            };

            // Отправляем на сервер
            fetch('/api/requests', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(requestData)
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error('HTTP error! status: ' + response.status);
                }
                return response.json();
            })
            .then(data => {
                // Закрываем модальное окно
                const modal = bootstrap.Modal.getInstance(document.getElementById('addRequestModal'));
                modal.hide();

                // Очищаем форму
                document.getElementById('addRequestForm').reset();
                clearDrawing();

                // Перезагружаем страницу для обновления списка
                window.location.reload();
            })
            .catch(error => {
                console.error('Ошибка при создании заявки:', error);
                alert('Ошибка при создании заявки: ' + error.message);
            });
        }

        // Инициализация обработчиков для модального окна
        document.addEventListener('DOMContentLoaded', function() {
            const drawBtn = document.getElementById('drawPolygonBtn');
            const clearBtn = document.getElementById('clearPolygonBtn');
            const saveBtn = document.getElementById('saveRequestBtn');
            const cancelDrawBtn = document.getElementById('cancelDrawingBtn');

            if (drawBtn) {
                drawBtn.addEventListener('click', function() {
                    startDrawing();
                });
            }

            if (clearBtn) {
                clearBtn.addEventListener('click', clearDrawing);
            }

            if (saveBtn) {
                saveBtn.addEventListener('click', saveRequest);
            }

            if (cancelDrawBtn) {
                cancelDrawBtn.addEventListener('click', cancelDrawing);
            }

            // Очистка при закрытии модального окна (только если не в режиме рисования)
            document.getElementById('addRequestModal').addEventListener('hidden.bs.modal', function() {
                if (!isDrawing) {
                    stopDrawing();
                    if (drawnEntity && viewer) {
                        viewer.entities.remove(drawnEntity);
                        drawnEntity = null;
                    }
                    drawnPoints = [];
                }
            });
        });





        function getSlotIndexFromVisibilityButton(button) {
            const dataSlotIndex = button.getAttribute('data-slot-index');
            if (dataSlotIndex !== null && dataSlotIndex !== '') {
                const parsedIndex = Number(dataSlotIndex);
                if (Number.isFinite(parsedIndex)) {
                    return parsedIndex;
                }
            }

            const onClickValue = button.getAttribute('onclick') || '';
            const matches = onClickValue.match(/viewSlot\((\d+)/);
            if (!matches) {
                return null;
            }

            const fallbackIndex = Number(matches[1]);
            return Number.isFinite(fallbackIndex) ? fallbackIndex : null;
        }

        function collectVisibleSlotsForBooking() {
            const visibleButtons = document.querySelectorAll('#slotsTableBody button[title="Скрыть на карте"]');
            const uniqueSlots = new Map();

            visibleButtons.forEach(button => {
                const slotIndex = getSlotIndexFromVisibilityButton(button);
                if (!Number.isFinite(slotIndex) || !currentSlotsData[slotIndex]) {
                    return;
                }

                const slot = currentSlotsData[slotIndex];
                const satelliteId = Number(slot.satelliteId);
                const cycle = Number(slot.cycle);
                const rawSlotNum = slot.slotNumber ?? slot.slotNum;
                const slotNum = Number(rawSlotNum);

                if (!Number.isFinite(satelliteId) || !Number.isFinite(slotNum) || !Number.isFinite(cycle)) {
                    return;
                }

                const slotKey = `${satelliteId}:${slotNum}:${cycle}`;
                if (!uniqueSlots.has(slotKey)) {
                    uniqueSlots.set(slotKey, {
                        satelliteId: satelliteId,
                        slotNum: slotNum,
                        cycle: cycle
                    });
                }
            });

            return Array.from(uniqueSlots.values());
        }

        function bookVisibleSlots(button) {
            if (!currentSlotsContext || currentSlotsContext.type !== 'request') {
                alert('Бронирование доступно только для интервалов покрытия заявки');
                return;
            }

            if (!currentRequestId) {
                alert('Нет выбранной заявки для бронирования');
                return;
            }

            const slots = collectVisibleSlotsForBooking();
            if (slots.length === 0) {
                alert('Нет слотов с активной кнопкой "Скрыть на карте"');
                return;
            }

            const requestBody = {
                requestId: String(currentRequestId),
                slots: slots
            };

            if (button) {
                button.disabled = true;
            }

            fetch('/api/slots/booking/request', {
                method: 'POST',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(requestBody)
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return response.json();
            })
            .then(json => {
                const bookedCount = Array.isArray(json) ? json.length : 0;
                alert(`Забронировано слотов: ${bookedCount}`);
            })
            .catch(error => {
                console.error('Ошибка при бронировании слотов:', error);
                alert('Ошибка при бронировании слотов: ' + error.message);
            })
            .finally(() => {
                if (button) {
                    button.disabled = false;
                }
            });
        }

        function cancelRequestBooking(button) {
            if (!currentSlotsContext || currentSlotsContext.type !== 'request') {
                alert('Отмена бронирования доступна только для отображаемой заявки');
                return;
            }

            if (!currentRequestId) {
                alert('Нет выбранной заявки для отмены бронирования');
                return;
            }

            if (button) {
                button.disabled = true;
            }

            fetch(`/api/slots/booking/request?requestId=${encodeURIComponent(String(currentRequestId))}`, {
                method: 'DELETE',
                headers: {
                    'Accept': 'application/json'
                }
            })
            .then(async response => {
                if (!response.ok) {
                    const rawError = await response.text();
                    let errorMessage = rawError;
                    try {
                        const parsedError = JSON.parse(rawError);
                        errorMessage = parsedError.error || parsedError.message || rawError;
                    } catch (_) {}
                    throw new Error(`HTTP error! status: ${response.status} message: ${errorMessage}`);
                }
                return response.json();
            })
            .then(result => {
                const cancelledCount = Number(result) || 0;
                alert(`Отменено бронирований: ${cancelledCount}`);
            })
            .catch(error => {
                console.error('Ошибка при отмене бронирования:', error);
                alert('Ошибка при отмене бронирования: ' + error.message);
            })
            .finally(() => {
                if (button) {
                    button.disabled = false;
                }
            });
        }

        // Управление видимостью всех слотов
function toggleAllSlotsVisibility(isVisible) {
    if (!currentSlotsContext || currentSlotsData.length === 0) return;

    const dataSource = viewer.dataSources.getByName(currentSlotsContext.dataSourceName)[0];

    if (!dataSource) {
        console.warn('DataSource не найден для слотов');
        return;
    }

    // Проходим по всем слотам и меняем их видимость
    currentSlotsData.forEach((slot, index) => {
        const entityName = slot.entityId || `slot_${slot.satelliteId}_${slot.cycle}_${slot.slotNumber}`;
        const entity = dataSource.entities.getById(entityName);

        if (entity) {
            entity.polygon.show = isVisible;
        }
    });

    // Обновляем все кнопки видимости в таблице
    const visibilityButtons = document.querySelectorAll('#slotsTableBody .btn-outline-primary, #slotsTableBody .btn-outline-secondary');
    visibilityButtons.forEach(button => {
        // Проверяем, что это кнопка видимости (имеет иконку глаза)
        const icon = button.querySelector('i');
        if (icon && (icon.classList.contains('bi-eye') || icon.classList.contains('bi-eye-slash'))) {
            updateVisibilityButton(button, isVisible);
        }
    });
}

    </script>
</th:block>
</body>
</html>
