{{define "base"}}
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{template "title" .}}</title>
    <link rel="stylesheet" href="/static/app.css">
    <script src="/static/vendor/tailwindcss.browser.js"></script>
    <script src="/static/vendor/htmx-1.9.10.min.js"></script>
    <style>
        .htmx-request { opacity: 0.5; }
        .line-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
    </style>
</head>
<body class="bg-gray-100 min-h-screen">
    <nav class="bg-white shadow-sm sticky top-0 z-40">
        <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="flex justify-between h-14">
                <div class="flex items-center space-x-8">
                    <a href="/" class="text-xl font-bold text-blue-600">QuoteForge</a>
                    <div class="hidden md:flex space-x-4">
                        <a href="/projects" class="text-gray-600 hover:text-gray-900 px-3 py-2 text-sm">Мои проекты</a>
                        <a href="/pricelists" class="text-gray-600 hover:text-gray-900 px-3 py-2 text-sm">Прайслисты</a>
                        <a href="/partnumber-books" class="text-gray-600 hover:text-gray-900 px-3 py-2 text-sm">Партномера</a>
                        <a href="/setup" class="text-gray-600 hover:text-gray-900 px-3 py-2 text-sm">Настройки</a>
                    </div>
                </div>
                <div class="flex items-center space-x-4">
                    <!-- Sync Status Indicator (htmx-powered) -->
                    <div id="sync-status"
                         class="flex items-center gap-3 text-sm"
                         hx-get="/partials/sync-status"
                         hx-trigger="load, refresh from:body, every 30s"
                         hx-swap="innerHTML">
                    </div>
                    <span id="db-user" class="text-sm text-gray-600"></span>
                    <a href="/api/support-bundle"
                       title="Скачать Support Bundle"
                       class="text-gray-400 hover:text-gray-600 transition-colors"
                       download>
                        <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
                            <polyline points="7 10 12 15 17 10"/>
                            <line x1="12" y1="15" x2="12" y2="3"/>
                        </svg>
                    </a>
                </div>
            </div>
        </div>
    </nav>

    <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
        {{template "content" .}}
    </main>

    <footer class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3 text-right">
        <span class="text-xs text-gray-400">v{{.AppVersion}}</span>
    </footer>

    <div id="toast" class="fixed bottom-4 right-4 z-50"></div>

    <!-- Dead-man's switch overlay: shown when backend process stops responding -->
    <div id="backend-offline-overlay" class="hidden fixed inset-0 z-[9999] bg-black/80 flex items-center justify-center p-6">
        <div class="bg-white rounded-xl shadow-2xl max-w-md w-full p-8 text-center">
            <div class="text-red-500 mb-4">
                <svg class="w-16 h-16 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
                </svg>
            </div>
            <h2 class="text-xl font-bold text-gray-900 mb-3">Приложение остановлено</h2>
            <p class="text-gray-600 mb-4">Консольное окно QuoteForge было закрыто — без него программа не работает.</p>
            <div class="bg-amber-50 border border-amber-200 rounded-lg p-3 mb-6 text-sm text-amber-800">
                Запустите программу заново и нажмите «Обновить страницу».
            </div>
            <button onclick="window.location.reload()" class="w-full px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium">
                Обновить страницу
            </button>
        </div>
    </div>

    <!-- Price Diff Modal -->
    <div id="price-diff-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden p-4">
        <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] flex flex-col">
            <div class="p-5 border-b border-gray-200 flex-shrink-0 flex justify-between items-center">
                <h3 class="text-lg font-semibold text-gray-900">Изменение цен</h3>
                <button onclick="closePriceDiffModal()" class="text-gray-400 hover:text-gray-600">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                    </svg>
                </button>
            </div>
            <div id="price-diff-modal-body" class="overflow-y-auto flex-1 p-5 space-y-5"></div>
            <div class="p-4 border-t border-gray-200 flex-shrink-0 flex justify-end">
                <button onclick="closePriceDiffModal()" class="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700 text-sm">Закрыть</button>
            </div>
        </div>
    </div>

    <!-- Sync Info Modal -->
    <div id="sync-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden p-4">
        <div class="bg-white rounded-lg shadow-xl max-w-lg w-full max-h-[90vh] flex flex-col">
            <div class="p-6 border-b border-gray-200 flex-shrink-0">
                <div class="flex justify-between items-center">
                    <h3 class="text-lg font-medium text-gray-900">Информация о синхронизации</h3>
                    <button onclick="closeSyncModal()" class="text-gray-400 hover:text-gray-500">
                        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                        </svg>
                    </button>
                </div>
            </div>

            <div class="overflow-y-auto flex-1">
                <div class="p-6 space-y-5">
                    <!-- Section 1: DB Connection -->
                    <div>
                        <h4 class="font-medium text-gray-900 mb-2">Подключение к БД</h4>
                        <div class="text-sm space-y-1">
                            <div class="flex justify-between">
                                <span class="text-gray-500">Адрес:</span>
                                <span id="modal-db-host" class="text-gray-700 font-mono">—</span>
                            </div>
                            <div class="flex justify-between">
                                <span class="text-gray-500">Пользователь:</span>
                                <span id="modal-db-user" class="text-gray-700">—</span>
                            </div>
                            <div class="flex justify-between">
                                <span class="text-gray-500">Статус:</span>
                                <span id="modal-db-status" class="text-gray-700">Проверка...</span>
                            </div>
                            <div class="flex justify-between">
                                <span class="text-gray-500">Последняя синхронизация:</span>
                                <span id="modal-last-sync" class="text-gray-700">—</span>
                            </div>
                        </div>
                    </div>

                    <div id="modal-readiness-section" class="hidden">
                        <h4 class="font-medium text-red-700 mb-2">Почему синхронизация недоступна</h4>
                        <div class="bg-red-50 border border-red-200 rounded px-3 py-2 text-sm">
                            <div id="modal-readiness-reason" class="text-red-700">—</div>
                            <div id="modal-readiness-min-version" class="text-red-600 text-xs mt-1 hidden"></div>
                        </div>
                    </div>

                    <div id="modal-pricelist-sync-issue" class="hidden">
                        <h4 class="font-medium text-red-700 mb-2">Состояние прайслистов</h4>
                        <div class="bg-red-50 border border-red-200 rounded px-3 py-2 text-sm space-y-1">
                            <div id="modal-pricelist-sync-summary" class="text-red-700">—</div>
                            <div id="modal-pricelist-sync-attempt" class="text-red-600 text-xs hidden"></div>
                            <div id="modal-pricelist-sync-error" class="text-red-600 text-xs hidden whitespace-pre-wrap"></div>
                        </div>
                    </div>

                    <!-- Section 2: Statistics -->
                    <div>
                        <h4 class="font-medium text-gray-900 mb-2">Статистика</h4>
                        <div class="grid grid-cols-2 gap-2 text-sm">
                            <div class="flex justify-between bg-gray-50 rounded px-3 py-1.5">
                                <span class="text-gray-500">Компоненты (lot):</span>
                                <span id="modal-lot-count" class="font-medium text-gray-700">—</span>
                            </div>
                            <div class="flex justify-between bg-gray-50 rounded px-3 py-1.5">
                                <span class="text-gray-500">Котировки:</span>
                                <span id="modal-lotlog-count" class="font-medium text-gray-700">—</span>
                            </div>
                            <div class="flex justify-between bg-gray-50 rounded px-3 py-1.5">
                                <span class="text-gray-500">Конфигурации:</span>
                                <span id="modal-config-count" class="font-medium text-gray-700">—</span>
                            </div>
                            <div class="flex justify-between bg-gray-50 rounded px-3 py-1.5">
                                <span class="text-gray-500">Проекты:</span>
                                <span id="modal-project-count" class="font-medium text-gray-700">—</span>
                            </div>
                        </div>
                    </div>

                    <!-- Section 3: Pending Changes (shown only if any) -->
                    <div id="modal-pending-section" class="hidden">
                        <h4 class="font-medium text-gray-900 mb-2">Ожидающие синхронизации</h4>
                        <div id="modal-pending-list" class="text-sm max-h-40 overflow-y-auto space-y-1"></div>
                    </div>

                    <!-- Section 4: Errors (shown only if any) -->
                    <div id="modal-errors-section" class="hidden">
                        <h4 class="font-medium text-gray-900 mb-2">Ошибки синхронизации</h4>
                        <div id="modal-errors-list" class="text-sm max-h-40 overflow-y-auto space-y-1"></div>
                    </div>

                    <!-- Section 5: Self-Healing (shown only if errors exist) -->
                    <div id="modal-repair-section" class="hidden">
                        <div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
                            <h4 class="font-medium text-blue-900 mb-2">Автоматическое исправление</h4>
                            <p class="text-sm text-blue-700 mb-3">
                                Система может исправить данные и очистить ошибки синхронизации:
                            </p>
                            <ul class="text-sm text-blue-700 mb-3 ml-4 list-disc space-y-1">
                                <li>Проверит и исправит названия проектов</li>
                                <li>Восстановит битые ссылки на проекты</li>
                                <li>Очистит ошибки и даст pending changes еще шанс</li>
                            </ul>
                            <button id="repair-button" onclick="repairPendingChanges()"
                                class="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed">
                                ИСПРАВИТЬ
                            </button>
                            <div id="repair-result" class="mt-2 text-sm hidden"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="p-6 border-t border-gray-200 flex-shrink-0">
                <div class="flex justify-end">
                    <button onclick="closeSyncModal()" class="px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700">
                        Закрыть
                    </button>
                </div>
            </div>
        </div>
    </div>

    <script>
        function showToast(msg, type) {
            const colors = { success: 'bg-green-500', error: 'bg-red-500', info: 'bg-blue-500' };
            const el = document.getElementById('toast');
            el.innerHTML = '<div class="' + (colors[type] || colors.info) + ' text-white px-4 py-2 rounded shadow">' + msg + '</div>';
            setTimeout(() => el.innerHTML = '', 3000);
        }

        // Open sync modal
        function openSyncModal() {
            const modal = document.getElementById('sync-modal');
            if (modal) {
                modal.classList.remove('hidden');
                // Load sync info when modal opens
                loadSyncInfo();
            }
        }

        // Close sync modal
        function closeSyncModal() {
            const modal = document.getElementById('sync-modal');
            if (modal) {
                modal.classList.add('hidden');
            }
        }

        // Load sync info for modal
        async function loadSyncInfo() {
            try {
                const resp = await fetch('/api/sync/info');
                const data = await resp.json();

                // Section 1: DB Connection
                document.getElementById('modal-db-host').textContent = data.db_host ? data.db_host + '/' + data.db_name : '—';
                document.getElementById('modal-db-user').textContent = data.db_user || '—';

                const statusEl = document.getElementById('modal-db-status');
                if (data.is_online) {
                    statusEl.innerHTML = '<span class="inline-block w-2 h-2 rounded-full bg-green-500 mr-1"></span>Online';
                } else {
                    statusEl.innerHTML = '<span class="inline-block w-2 h-2 rounded-full bg-red-500 mr-1"></span>Offline';
                }

                if (data.last_sync_at) {
                    const date = new Date(data.last_sync_at);
                    document.getElementById('modal-last-sync').textContent = date.toLocaleString('ru-RU');
                } else {
                    document.getElementById('modal-last-sync').textContent = '—';
                }

                const readinessSection = document.getElementById('modal-readiness-section');
                const readinessReason = document.getElementById('modal-readiness-reason');
                const readinessMinVersion = document.getElementById('modal-readiness-min-version');
                if (data.readiness && data.readiness.blocked) {
                    readinessSection.classList.remove('hidden');
                    readinessReason.textContent = data.readiness.reason_text || 'Синхронизация заблокирована preflight-проверкой.';
                    if (data.readiness.required_min_app_version) {
                        readinessMinVersion.classList.remove('hidden');
                        readinessMinVersion.textContent = 'Требуется обновление до версии ' + data.readiness.required_min_app_version;
                    } else {
                        readinessMinVersion.classList.add('hidden');
                        readinessMinVersion.textContent = '';
                    }
                } else {
                    readinessSection.classList.add('hidden');
                    readinessReason.textContent = '';
                    readinessMinVersion.classList.add('hidden');
                    readinessMinVersion.textContent = '';
                }

                const syncIssueSection = document.getElementById('modal-pricelist-sync-issue');
                const syncIssueSummary = document.getElementById('modal-pricelist-sync-summary');
                const syncIssueAttempt = document.getElementById('modal-pricelist-sync-attempt');
                const syncIssueError = document.getElementById('modal-pricelist-sync-error');
                const hasSyncFailure = data.last_pricelist_sync_status === 'failed';
                if (data.has_incomplete_server_sync) {
                    syncIssueSection.classList.remove('hidden');
                    syncIssueSummary.textContent = 'Последняя синхронизация прайслистов прервалась. На сервере есть изменения, которые еще не загружены локально.';
                } else if (hasSyncFailure) {
                    syncIssueSection.classList.remove('hidden');
                    syncIssueSummary.textContent = 'Последняя синхронизация прайслистов завершилась ошибкой.';
                } else {
                    syncIssueSection.classList.add('hidden');
                    syncIssueSummary.textContent = '';
                }
                if (syncIssueSection.classList.contains('hidden')) {
                    syncIssueAttempt.classList.add('hidden');
                    syncIssueAttempt.textContent = '';
                    syncIssueError.classList.add('hidden');
                    syncIssueError.textContent = '';
                } else {
                    if (data.last_pricelist_attempt_at) {
                        syncIssueAttempt.classList.remove('hidden');
                        syncIssueAttempt.textContent = 'Последняя попытка: ' + new Date(data.last_pricelist_attempt_at).toLocaleString('ru-RU');
                    } else {
                        syncIssueAttempt.classList.add('hidden');
                        syncIssueAttempt.textContent = '';
                    }
                    if (data.last_pricelist_sync_error) {
                        syncIssueError.classList.remove('hidden');
                        syncIssueError.textContent = data.last_pricelist_sync_error;
                    } else {
                        syncIssueError.classList.add('hidden');
                        syncIssueError.textContent = '';
                    }
                }

                // Section 2: Statistics
                document.getElementById('modal-lot-count').textContent = data.is_online ? data.lot_count.toLocaleString() : '—';
                document.getElementById('modal-lotlog-count').textContent = data.is_online ? data.lot_log_count.toLocaleString() : '—';
                document.getElementById('modal-config-count').textContent = data.config_count.toLocaleString();
                document.getElementById('modal-project-count').textContent = data.project_count.toLocaleString();

                // Section 3: Pending changes
                const pendingSection = document.getElementById('modal-pending-section');
                const pendingList = document.getElementById('modal-pending-list');
                if (data.pending_changes && data.pending_changes.length > 0) {
                    pendingSection.classList.remove('hidden');
                    pendingList.innerHTML = data.pending_changes.map(ch => {
                        const shortUUID = ch.entity_uuid.substring(0, 8);
                        const time = new Date(ch.created_at).toLocaleString('ru-RU');
                        const hasError = ch.last_error ? ' border-l-2 border-red-400 pl-2' : '';
                        const errorLine = ch.last_error ? `<div class="text-red-500 text-xs mt-0.5">${ch.last_error}</div>` : '';
                        return `<div class="bg-gray-50 rounded px-3 py-1.5${hasError}">
                            <span class="font-medium">${ch.operation}</span>
                            <span class="text-gray-500">${ch.entity_type}</span>
                            <span class="font-mono text-xs text-gray-400">${shortUUID}</span>
                            <span class="text-gray-400 text-xs ml-1">${time}</span>
                            ${errorLine}
                        </div>`;
                    }).join('');
                } else {
                    pendingSection.classList.add('hidden');
                }

                // Section 4: Errors
                const errorsSection = document.getElementById('modal-errors-section');
                const errorsList = document.getElementById('modal-errors-list');
                const hasErrors = data.errors && data.errors.length > 0;
                if (hasErrors) {
                    errorsSection.classList.remove('hidden');
                    errorsList.innerHTML = data.errors.map(error => {
                        const time = new Date(error.timestamp).toLocaleString('ru-RU');
                        return `<div class="bg-red-50 text-red-700 rounded px-3 py-1.5">
                            <span class="text-xs text-red-400">${time}</span>: ${error.message}
                        </div>`;
                    }).join('');
                } else {
                    errorsSection.classList.add('hidden');
                }

                // Section 5: Repair (show only if errors exist)
                const repairSection = document.getElementById('modal-repair-section');
                const repairResult = document.getElementById('repair-result');
                if (hasErrors) {
                    repairSection.classList.remove('hidden');
                    repairResult.classList.add('hidden');
                    repairResult.innerHTML = '';
                } else {
                    repairSection.classList.add('hidden');
                }
            } catch(e) {
                console.error('Failed to load sync info:', e);
                document.getElementById('modal-db-status').textContent = 'Ошибка загрузки';
            }
        }

        // Repair pending changes
        async function repairPendingChanges() {
            const button = document.getElementById('repair-button');
            const resultDiv = document.getElementById('repair-result');

            button.disabled = true;
            button.textContent = 'Исправление...';
            resultDiv.classList.add('hidden');

            try {
                const resp = await fetch('/api/sync/repair', { method: 'POST' });
                const data = await resp.json();

                if (data.success) {
                    resultDiv.classList.remove('hidden');
                    if (data.repaired > 0) {
                        resultDiv.className = 'mt-2 text-sm text-green-700 bg-green-50 rounded px-3 py-2';
                        resultDiv.textContent = `✓ Исправлено: ${data.repaired}`;
                        // Reload sync info after repair
                        setTimeout(() => loadSyncInfo(), 1000);
                    } else {
                        resultDiv.className = 'mt-2 text-sm text-yellow-700 bg-yellow-50 rounded px-3 py-2';
                        resultDiv.textContent = 'Нечего исправлять или проблемы остались';
                        if (data.remaining_errors && data.remaining_errors.length > 0) {
                            resultDiv.innerHTML += '<div class="mt-1 text-xs">' + data.remaining_errors.join('<br>') + '</div>';
                        }
                    }
                } else {
                    resultDiv.classList.remove('hidden');
                    resultDiv.className = 'mt-2 text-sm text-red-700 bg-red-50 rounded px-3 py-2';
                    resultDiv.textContent = 'Ошибка: ' + (data.error || 'неизвестная ошибка');
                }
            } catch (e) {
                resultDiv.classList.remove('hidden');
                resultDiv.className = 'mt-2 text-sm text-red-700 bg-red-50 rounded px-3 py-2';
                resultDiv.textContent = 'Ошибка запроса: ' + e.message;
            } finally {
                button.disabled = false;
                button.textContent = 'ИСПРАВИТЬ';
            }
        }

        // Event delegation for sync dropdown and actions
        document.addEventListener('DOMContentLoaded', function() {
            loadDBUser();
            checkWritePermission();
        });

        // Event delegation for sync actions
        document.body.addEventListener('click', function(e) {
            // Handle sync button click (full sync only)
            const syncButton = e.target.closest('#sync-button');
            if (syncButton) {
                e.stopPropagation();
                const button = syncButton;

                // Add loading state
                const originalHTML = button.innerHTML;
                button.disabled = true;
                button.innerHTML = '<svg class="animate-spin w-4 h-4 inline mr-2" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>';

                fullSync(button, originalHTML);
            }
        });

        // Refactored sync action function to reduce duplication
        async function syncAction(endpoint, successMessage, button, originalHTML) {
            try {
                const resp = await fetch(endpoint, { method: 'POST' });
                const data = await resp.json();

                if (data.success) {
                    showToast(successMessage, 'success');
                    // Update last sync time - removed since dropdown is gone
                    // loadLastSyncTime();

                    // Dispatch custom event for pages to react to sync completion
                    window.dispatchEvent(new CustomEvent('sync-completed', {
                        detail: {
                            endpoint: endpoint,
                            data: data
                        }
                    }));
                } else if (resp.status === 423) {
                    const reason = data.reason_text || data.error || 'Синхронизация заблокирована.';
                    showToast(reason, 'error');
                    openSyncModal();
                    loadSyncInfo();
                } else {
                    showToast('Ошибка: ' + (data.error || 'неизвестная ошибка'), 'error');
                }

                htmx.trigger('#sync-status', 'refresh');
            } catch (error) {
                showToast('Ошибка: ' + error.message, 'error');
            } finally {
                // Reset button state
                if (button) {
                    button.disabled = false;
                    button.innerHTML = originalHTML;
                }
            }
        }

        function pushPendingChanges(button, originalHTML) {
            syncAction('/api/sync/push', 'Изменения синхронизированы', button, originalHTML);
        }

        function fullSync(button, originalHTML) {
            syncAction('/api/sync/all', 'Полная синхронизация завершена', button, originalHTML);
        }

        async function loadDBUser() {
            try {
                const resp = await fetch('/api/db-status');
                const data = await resp.json();
                const userEl = document.getElementById('db-user');
                if (data.connected && data.db_user) {
                    userEl.innerHTML = '<span class="text-gray-500">@</span>' + data.db_user;
                }
            } catch(e) {
                // ignore
            }
        }

        // Admin pricing link is now always visible
        // Write permission is checked at operation time (create/delete)
        async function checkWritePermission() {
            // No longer needed - link always visible in offline-first mode
            // Operations will check online status when executed
        }

        // Load last sync time for dropdown (removed since dropdown is gone)
        // async function loadLastSyncTime() {
        //     try {
        //         const resp = await fetch('/api/sync/status');
        //         const data = await resp.json();
        //         if (data.last_pricelist_sync) {
        //             const date = new Date(data.last_pricelist_sync);
        //             document.getElementById('last-sync-time').textContent = date.toLocaleString('ru-RU');
        //         } else {
        //             document.getElementById('last-sync-time').textContent = 'Нет данных';
        //         }
        //     } catch(e) {
        //         console.error('Failed to load last sync time:', e);
        //     }
        // }

        // ==================== SHARED PRICE REFRESH UTILITIES ====================

        async function fetchLatestEstimatePricelistId() {
            try {
                const resp = await fetch('/api/pricelists?active_only=true&source=estimate&per_page=1');
                if (!resp.ok) return null;
                const data = await resp.json();
                const list = data.pricelists || data.items || data;
                if (Array.isArray(list) && list.length > 0) return Number(list[0].id);
            } catch(_) {}
            return null;
        }

        function _fmtMoneyDiff(value) {
            if (!Number.isFinite(Number(value))) return 'N/A';
            return '$ ' + Math.round(Number(value)).toLocaleString('ru-RU');
        }

        function _fmtArrow(prev, next) {
            const diff = next - prev;
            if (Math.abs(diff) < 0.5) return '';
            const pct = prev > 0 ? Math.round((diff / prev) * 100) : 0;
            const sign = diff > 0 ? '+' : '';
            const color = diff > 0 ? 'text-red-600' : 'text-green-600';
            return ` <span class="${color} text-xs font-medium">(${sign}${pct}%)</span>`;
        }

        function _buildDiffRow(lot, qty, prev, next) {
            const prevLine = prev * qty;
            const nextLine = next * qty;
            const delta = next - prev;
            const arrowColor = delta > 0 ? 'text-red-600' : 'text-green-600';
            return `<tr class="border-b border-gray-100 last:border-0">
                <td class="py-1.5 pr-3 text-sm text-gray-700 font-mono">${lot}</td>
                <td class="py-1.5 px-2 text-sm text-right text-gray-500">${qty}</td>
                <td class="py-1.5 px-2 text-sm text-right whitespace-nowrap">
                    <span class="text-gray-400 line-through text-xs">${_fmtMoneyDiff(prev)}</span>
                    <span class="${arrowColor} font-medium ml-1">${_fmtMoneyDiff(next)}</span>
                </td>
                <td class="py-1.5 pl-2 text-sm text-right whitespace-nowrap">
                    <span class="text-gray-400 line-through text-xs">${_fmtMoneyDiff(prevLine)}</span>
                    <span class="${arrowColor} font-medium ml-1">${_fmtMoneyDiff(nextLine)}</span>
                </td>
            </tr>`;
        }

        function showPriceDiffModal(results) {
            const body = document.getElementById('price-diff-modal-body');
            if (!body) return;

            const sections = results.filter(r => !r.skipped);
            if (sections.length === 0) {
                body.innerHTML = '<p class="text-gray-500 text-sm text-center py-4">Обновление цен отключено для всех конфигураций</p>';
                document.getElementById('price-diff-modal').classList.remove('hidden');
                return;
            }

            let html = '';
            let anyChanges = false;

            for (const r of sections) {
                if (r.error) {
                    html += `<div class="text-sm text-red-600 bg-red-50 rounded px-3 py-2">${r.configName ? `<span class="font-medium">${r.configName}:</span> ` : ''}Ошибка обновления цен</div>`;
                    continue;
                }

                const diffs = (r.itemDiffs || []).filter(d => Math.abs(d.prevPrice - d.newPrice) > 0.01);
                const totalDelta = (r.newTotal || 0) - (r.prevTotal || 0);

                if (results.length > 1) {
                    html += `<div class="text-sm font-semibold text-gray-800 mb-1">${r.configName || '—'}</div>`;
                }

                if (diffs.length === 0) {
                    html += `<div class="text-sm text-gray-500 bg-gray-50 rounded px-3 py-2 mb-2">Изменений нет</div>`;
                } else {
                    anyChanges = true;
                    html += `<div class="overflow-x-auto mb-2">
                        <table class="w-full text-left">
                            <thead>
                                <tr class="border-b border-gray-200 text-xs text-gray-500 uppercase">
                                    <th class="pb-1 pr-3 font-medium">Компонент</th>
                                    <th class="pb-1 px-2 text-right font-medium">Кол.</th>
                                    <th class="pb-1 px-2 text-right font-medium">Цена / шт.</th>
                                    <th class="pb-1 pl-2 text-right font-medium">Сумма</th>
                                </tr>
                            </thead>
                            <tbody>${diffs.map(d => _buildDiffRow(d.lot_name, d.quantity, d.prevPrice, d.newPrice)).join('')}</tbody>
                        </table>
                    </div>`;
                }

                const totalColor = totalDelta > 0 ? 'text-red-600' : totalDelta < 0 ? 'text-green-600' : 'text-gray-600';
                const totalArrow = _fmtArrow(r.prevTotal || 0, r.newTotal || 0);
                const totalPrevHtml = totalDelta !== 0
                    ? `<span class="text-gray-400 line-through text-xs mr-1">${_fmtMoneyDiff(r.prevTotal || 0)}</span>`
                    : '';
                html += `<div class="flex justify-between items-center text-sm bg-gray-50 rounded px-3 py-2 mb-1">
                    <span class="text-gray-600 font-medium">Итог конфигурации</span>
                    <span>
                        ${totalPrevHtml}<span class="${totalColor} font-semibold">${_fmtMoneyDiff(r.newTotal || 0)}</span>${totalArrow}
                    </span>
                </div>`;
            }

            if (!anyChanges && sections.every(r => !r.error)) {
                html = '<div class="text-sm text-gray-500 text-center py-6">Цены актуальны — изменений нет</div>' + html;
            }

            body.innerHTML = html;
            document.getElementById('price-diff-modal').classList.remove('hidden');
        }

        function closePriceDiffModal() {
            document.getElementById('price-diff-modal')?.classList.add('hidden');
        }

        // Call functions immediately to ensure they run even before DOMContentLoaded
        // This ensures username and admin link are visible ASAP
        loadDBUser();
        checkWritePermission();

        // Dead-man's switch: detect if the backend process has stopped
        (function() {
            const POLL_MS = 5000;
            const FAIL_THRESHOLD = 2;
            let failCount = 0;

            async function checkBackend() {
                try {
                    const ctrl = new AbortController();
                    const timer = setTimeout(() => ctrl.abort(), 3000);
                    const resp = await fetch('/health', { signal: ctrl.signal });
                    clearTimeout(timer);
                    if (resp.ok) {
                        failCount = 0;
                        document.getElementById('backend-offline-overlay').classList.add('hidden');
                    } else {
                        failCount++;
                    }
                } catch (_) {
                    failCount++;
                }
                if (failCount >= FAIL_THRESHOLD) {
                    document.getElementById('backend-offline-overlay').classList.remove('hidden');
                }
            }

            setInterval(checkBackend, POLL_MS);
        })();

        // Load last sync time - removed since dropdown is gone
        // document.addEventListener('DOMContentLoaded', loadLastSyncTime);
    </script>
</body>
</html>
{{end}}
