// Парсинг аудитории — локальный SPAMIMPAKTER (из undergroundbrand.ru)
(function () {
  const API_URL = window.API_URL || '/api';

function ugAlert(message, type) {
  if (typeof showNotification === 'function') showNotification(message, type || 'info');
  else alert(message);
}
function ugConfirm(message) {
  return Promise.resolve(confirm(message));
}
function copyText(text, el) {
  navigator.clipboard.writeText(text).then(() => {
    if (el) { const o = el.textContent; el.textContent = '✓'; setTimeout(() => { el.textContent = o; }, 800); }
  });
}

// PARSER FUNCTIONS — Парсинг аудитории
        // ============================================================================

        let parserJobs = [];
        let parserRefreshInterval = null;
        let parserJobsLoading = false;
        let currentParserResultJobId = null;

        function startParserJobsRefresh() {
            if (parserRefreshInterval) clearInterval(parserRefreshInterval);
            parserRefreshInterval = setInterval(() => {
                if (document.getElementById('tab-parsing')?.classList.contains('active')) {
                    loadParserJobs();
                }
            }, 5000);
        }

        async function loadParserJobs() {
            const container = document.getElementById('parserJobsList');
            if (!container || parserJobsLoading) return;
            parserJobsLoading = true;
            try {
                const ctrl = new AbortController();
                const timer = setTimeout(() => ctrl.abort(), 12000);
                const res = await fetch(`${API_URL}/parser/jobs?limit=20`, {
                    signal: ctrl.signal,
                });
                clearTimeout(timer);
                if (!res.ok) throw new Error(`HTTP ${res.status}`);
                const data = await res.json();
                parserJobs = data.jobs || [];
                renderParserJobs();
            } catch (err) {
                console.error('Error loading parser jobs:', err);
            } finally {
                parserJobsLoading = false;
            }
        }

        function parserJobCanResume(job) {
            return job.status === 'paused' || (
                (job.total_messages || 0) > 0 ||
                (job.total_users || 0) > 0 ||
                (job.progress_percent || 0) > 0
            );
        }

        function renderParserJobs() {
            const container = document.getElementById('parserJobsList');
            if (!parserJobs.length) {
                container.innerHTML = '<p style="color: var(--text-secondary); text-align: center; padding: 20px;">Нет задач. Нажмите «Создать задачу» чтобы начать парсинг.</p>';
                return;
            }

            container.innerHTML = parserJobs.map(job => {
                const statusInfo = getParserStatusInfo(job.status);
                const canResume = parserJobCanResume(job);
                let actionButtons = '';
                if (job.status === 'pending') {
                    actionButtons = `
                        <button onclick="event.stopPropagation();startParserJob(${job.id})" class="btn-small btn-primary">Запустить</button>
                        <button onclick="event.stopPropagation();deleteParserJob(${job.id})" class="btn-small btn-secondary">Удалить</button>`;
                } else if (job.status === 'running') {
                    actionButtons = `<button onclick="event.stopPropagation();stopParserJob(${job.id})" class="btn-small btn-error">Стоп</button>`;
                } else if (job.status === 'paused') {
                    actionButtons = `
                        <button onclick="event.stopPropagation();resumeParserJob(${job.id})" class="btn-small btn-primary">Продолжить</button>
                        ${canResume ? `<button onclick="event.stopPropagation();restartParserJob(${job.id})" class="btn-small btn-secondary">Заново</button>` : ''}
                        <button onclick="event.stopPropagation();deleteParserJob(${job.id})" class="btn-small btn-secondary">Удалить</button>`;
                } else if (job.status === 'failed') {
                    actionButtons = canResume ? `
                        <button onclick="event.stopPropagation();resumeParserJob(${job.id})" class="btn-small btn-primary">Продолжить</button>
                        <button onclick="event.stopPropagation();restartParserJob(${job.id})" class="btn-small btn-secondary">Заново</button>
                        <button onclick="event.stopPropagation();deleteParserJob(${job.id})" class="btn-small btn-secondary">Удалить</button>` : `
                        <button onclick="event.stopPropagation();startParserJob(${job.id})" class="btn-small btn-primary">Перезапустить</button>
                        <button onclick="event.stopPropagation();deleteParserJob(${job.id})" class="btn-small btn-secondary">Удалить</button>`;
                } else {
                    // completed, cancelled
                    actionButtons = `
                        <button onclick="event.stopPropagation();restartParserJob(${job.id})" class="btn-small btn-primary">Перезапустить</button>
                        ${job.total_users > 0 ? `<button onclick="event.stopPropagation();openParserResults(${job.id})" class="btn-small btn-primary">Результаты</button>` : ''}
                        <button onclick="event.stopPropagation();deleteParserJob(${job.id})" class="btn-small btn-secondary">Удалить</button>`;
                }

                let progressBar = '';
                if (job.status === 'running' || job.status === 'paused') {
                    progressBar = `<div style="width:100%;height:3px;background:var(--border);border-radius:2px;margin-top:4px;"><div style="width:${job.progress_percent}%;height:100%;background:var(--primary);border-radius:2px;transition:width 0.5s;"></div></div>`;
                }

                return `
                    <div class="job-card" style="background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; cursor:pointer;" onclick="openParserResults(${job.id})">
                        <div style="display: flex; justify-content: space-between; align-items: center; gap: 10px;">
                            <div style="flex:1; min-width: 0;">
                                <div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap;">
                                    <span style="font-size:0.85rem;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${escapeHtml(job.group_title || job.group_link)}</span>
                                    <span style="font-size:0.68rem;color:var(--text-secondary);background:var(--bg-hover);padding:2px 6px;border-radius:4px;">${getParserModeName(job.parse_mode)}</span>
                                    <span class="status-badge ${statusInfo.class}" style="font-size:0.65rem;">${statusInfo.icon} ${statusInfo.text}</span>
                                </div>
                                <p style="margin:1px 0 0;font-size:0.7rem;color:var(--text-secondary);">
                                    ${job.account_username ? '@' + escapeHtml(job.account_username) : escapeHtml(job.account_phone)} •
                                    ${job.total_messages > 0 ? `${job.total_messages} сообщ. → ` : ''}
                                    <span style="color:var(--success);">${job.total_users} юзеров</span>
                                    ${job.users_with_username > 0 ? ` (<span style="color:var(--primary);">${job.users_with_username} с тегом</span>)` : ''}
                                    ${job.status !== 'failed' && job.current_status ? ` • ${escapeHtml(job.current_status)}` : ''}
                                </p>
                                ${(job.parse_mode === 'single_topic' || job.parse_mode === 'ai_parse') && job.topic_link ? `<p style="margin:2px 0 0;font-size:0.68rem;color:var(--text-secondary);word-break:break-all;">Группа: ${escapeHtml(job.group_link)} • Топик: ${escapeHtml(job.topic_link)}</p>` : ''}
                                ${job.status === 'failed' && job.error_message ? `<p style="margin:4px 0 0;font-size:0.72rem;color:var(--error);line-height:1.35;">${escapeHtml(job.error_message)}</p>` : ''}
                                ${job.status === 'paused' && job.error_message ? `<p style="margin:4px 0 0;font-size:0.72rem;color:var(--text-secondary);line-height:1.35;">${escapeHtml(job.error_message)}</p>` : ''}
                                ${progressBar}
                            </div>
                            <div style="display:flex;align-items:center;gap:5px;flex-shrink:0;">
                                ${actionButtons}
                            </div>
                        </div>
                    </div>
                `;
            }).join('');
        }

        function getParserStatusInfo(status) {
            const info = {
                'pending': { icon: '⏳', text: 'Ожидание', class: 'status-warning' },
                'running': { icon: '<span class="status-spinner"></span>', text: 'Парсинг...', class: 'status-warning' },
                'paused': { icon: '⏸️', text: 'Пауза', class: 'status-warning' },
                'completed': { icon: '✅', text: 'Завершено', class: 'status-success' },
                'failed': { icon: '❌', text: 'Ошибка', class: 'status-error' },
                'cancelled': { icon: '🛑', text: 'Остановлено', class: 'status-error' }
            };
            return info[status] || { icon: '?', text: status, class: '' };
        }

        function getParserModeName(mode) {
            const modes = {
                'members': '👥 Участники',
                'messages': '💬 Писавшие в чат',
                'dialog': '🗣️ Диалог',
                'comments': '💭 Комментарии',
                'topics': '📌 По темам',
                'single_topic': '🎯 Топик',
                'ai_parse': '🤖 ИИ-парсер'
            };
            return modes[mode] || mode || '👥 Участники';
        }

        // ============================================================================
        // PARSER MODAL - Новый табличный выбор аккаунта (как в прогреве)
        // ============================================================================
        let parserModalAccounts = [];
        let parserModalFiltered = [];
        let parserModalSelectedId = null;
        let parserModalPage = 1;
        let parserModalPerPage = 10;
        let parserPicker = null;

        async function openCreateParserModal() {
            try {
                if (window.__ugParserReady) await window.__ugParserReady;
                const modal = document.getElementById('createParserModal');
                if (!modal) {
                    ugAlert('Модалка парсера не загружена. Обновите страницу (Ctrl+F5).', 'error');
                    return;
                }
                if (typeof AccountPicker !== 'function') {
                    ugAlert('Компонент выбора аккаунтов не загружен. Обновите страницу (Ctrl+F5).', 'error');
                    return;
                }
                parserModalAccounts = [];
                parserModalFiltered = [];
                parserModalSelectedId = null;
                parserModalPage = 1;
                if (parserPicker) { parserPicker.destroy(); parserPicker = null; }

                document.getElementById('parserModalStep1').style.display = 'block';
                document.getElementById('parserModalStep2').style.display = 'none';
                modal.classList.add('show');
                document.body.classList.add('ug-bc-modal-open');

                document.getElementById('parserGroupInput').value = '';
                const topicInput = document.getElementById('parserTopicLinkInput');
                if (topicInput) topicInput.value = '';
                document.getElementById('parserLimitInput').value = '0';
                document.getElementById('parserDelayInput').value = '3';
                document.getElementById('parserUseProxy').checked = true;
                parserRangeTypeChanged('limit');
                document.getElementById('parserAutoProxySwitch').checked = true;
                document.getElementById('parserModalError').textContent = '';
                parserSourceTypeChanged();
                parserParseModeChanged();

                await parserModalLoadAccounts();
            } catch (err) {
                console.error('openCreateParserModal:', err);
                ugAlert('Не удалось открыть парсер: ' + err.message, 'error');
            }
        }

        async function parserModalLoadAccounts() {
            if (parserPicker) parserPicker.destroy();
            parserPicker = new AccountPicker({
                containerId: 'parserPickerContainer',
                mode: 'single',
                perPage: 10,
                accentColor: 'var(--primary)',
                customIsDisabled: (acc) => {
                    const deadStatuses = ['dead','banned','session_revoked','deactivated','frozen','no_session'];
                    const inParsing = acc.busy_in === 'parsing' || acc.in_parsing;
                    const inBroadcast = acc.busy_in === 'sending' || acc.busy_in === 'broadcast' || acc.in_broadcast;
                    return inParsing || inBroadcast || deadStatuses.includes(acc.status) || !acc.has_session;
                },
                onSelectionChange: (selectedId, count) => {
                    parserModalSelectedId = selectedId;
                    const btn = document.getElementById('parserModalNextBtn');
                    if (btn) { btn.disabled = !selectedId; btn.style.opacity = selectedId ? '1' : '0.5'; }
                }
            });
            
            try {
                const res = await fetch(`${API_URL}/accounts/for-warmup?has_session=true`, {
                });
                if (!res.ok) throw new Error('Не удалось загрузить аккаунты');
                const data = await res.json();
                // Передаём ВСЕ аккаунты, фильтрация через UI
                parserModalAccounts = data.accounts || [];
                
                const projectsRes = await fetch(`${API_URL}/projects`, {
                });
                if (projectsRes.ok) {
                    const projectsData = await projectsRes.json();
                    parserPicker.setProjects(projectsData.projects || []);
                }
                
                parserPicker.setAccounts(parserModalAccounts);
            } catch (err) {
                document.getElementById('parserPickerContainer').innerHTML = `<div style="padding:30px;text-align:center;color:var(--error);">${escapeHtml(err.message)}</div>`;
            }
        }


        function parserModalNextStep() {
            if (!parserModalSelectedId) return;
            const acc = parserModalAccounts.find(a => a.id === parserModalSelectedId);
            const label = acc ? `${acc.first_name || ''} ${acc.last_name || ''}`.trim() : '';
            const phone = acc ? acc.phone : '';
            const username = acc && acc.username ? `@${acc.username}` : '';
            document.getElementById('parserModalSelectedAccount').innerHTML = 
                `<span style="color:var(--primary);font-weight:600;">&#10003;</span> ${label || phone} ${username ? `<span style="color:var(--text-secondary);">${username}</span>` : ''} <span style="color:var(--text-secondary);margin-left:8px;">${phone}</span>`;
            
            document.getElementById('parserModalStep1').style.display = 'none';
            document.getElementById('parserModalStep2').style.display = 'block';
            // focus на поле ввода чтобы вставка работала сразу
            setTimeout(() => document.getElementById('parserGroupInput').focus(), 50);
        }

        function parserModalPrevStep() {
            document.getElementById('parserModalStep1').style.display = 'block';
            document.getElementById('parserModalStep2').style.display = 'none';
        }

        function closeParserModal() {
            document.getElementById('createParserModal')?.classList.remove('show');
            if (!document.querySelector('#ugParserModals .modal-overlay.show')) {
                document.body.classList.remove('ug-bc-modal-open');
            }
        }

        // ========== TGLab-style Parser UI Functions ==========
        function parserSourceTypeChanged() {
            const sourceType = document.getElementById('parserSourceType').value;
            const parseModeSelect = document.getElementById('parserParseMode');
            // Reset options based on source type
            if (sourceType === 'channel') {
                parseModeSelect.innerHTML = `
                    <option value="comments">💭 Комментарии канала</option>
                    <option value="messages">💬 Все сообщения обсуждения</option>
                    <option value="ai_parse">🤖 ИИ-парсер (умный отбор)</option>
                `;
            } else {
                // Для группы: участники, писавшие в чат, форум-топики
                // Комментарии под постами — только для каналов!
                parseModeSelect.innerHTML = `
                    <option value="members">👥 По участникам</option>
                    <option value="messages">💬 Писавшие в чат</option>
                    <option value="topics">📌 По темам (форум)</option>
                    <option value="single_topic">🎯 Один топик (ссылка)</option>
                    <option value="ai_parse">🤖 ИИ-парсер (умный отбор)</option>
                `;
            }
            parserParseModeChanged();
        }

        function parserParseModeChanged() {
            const parseMode = document.getElementById('parserParseMode').value;
            const dateRangeBlock = document.getElementById('parserDateRangeBlock');
            const activityWrap = document.getElementById('parserActivityWrap');
            const activitySelect = document.getElementById('parserActivityFilter');
            const modeHint = document.getElementById('parserModeHint');
            const topicRow = document.getElementById('parserTopicLinkRow');
            const topicLabel = document.getElementById('parserTopicLinkLabel');
            const aiPromptRow = document.getElementById('parserAiPromptRow');
            const groupInput = document.getElementById('parserGroupInput');
            const groupLabel = document.getElementById('parserGroupLinkLabel');

            if (topicRow) topicRow.style.display = (parseMode === 'single_topic' || parseMode === 'ai_parse') ? 'block' : 'none';
            if (topicLabel) {
                const sourceType = document.getElementById('parserSourceType')?.value || 'group';
                if (parseMode === 'ai_parse' && sourceType === 'channel') {
                    topicLabel.textContent = 'Ссылка на пост канала (необязательно — иначе все посты)';
                } else if (parseMode === 'ai_parse') {
                    topicLabel.textContent = 'Ссылка на топик (необязательно — для одной темы)';
                } else {
                    topicLabel.textContent = 'Ссылка на топик';
                }
            }
            if (aiPromptRow) aiPromptRow.style.display = parseMode === 'ai_parse' ? 'block' : 'none';
            if (groupInput && groupLabel) {
                const sourceType = document.getElementById('parserSourceType')?.value || 'group';
                if (parseMode === 'ai_parse' && sourceType === 'channel') {
                    groupLabel.textContent = 'Ссылка на канал';
                    groupInput.placeholder = '@channel или t.me/channel';
                } else if (parseMode === 'single_topic' || parseMode === 'ai_parse') {
                    groupLabel.textContent = 'Ссылка на группу (для вступления)';
                    groupInput.placeholder = 't.me/+invite, @username, -100... или из «Мои группы»';
                } else if (parseMode === 'topics') {
                    groupLabel.textContent = 'Ссылка на форум-группу';
                    groupInput.placeholder = 't.me/+invite, @group или -100... (для приватных — invite)';
                } else {
                    groupLabel.textContent = 'Ссылка на группу / канал';
                    groupInput.placeholder = 't.me/group, @username или ID';
                }
            }

            // Show date range only for messages/comments/topics/dialog modes
            if (parseMode === 'messages' || parseMode === 'comments' || parseMode === 'topics' || parseMode === 'single_topic' || parseMode === 'dialog' || parseMode === 'ai_parse') {
                dateRangeBlock.style.display = 'block';
            } else {
                dateRangeBlock.style.display = 'none';
            }

            // Фильтр активности имеет смысл только для режима "Участники".
            if (parseMode === 'members') {
                activityWrap.style.display = 'block';
            } else {
                activitySelect.value = 'all';
                activityWrap.style.display = 'none';
            }

            // Короткие пояснения по режимам, чтобы не было путаницы.
            if (parseMode === 'members') {
                modeHint.textContent = 'Участники: собираем участников чата/группы. Фильтр по статусам отбирает по last seen (был недавно / на этой неделе / в этом месяце / давно).';
            } else if (parseMode === 'messages') {
                modeHint.textContent = 'Писавшие: собираем авторов всех сообщений за выбранный период/лимит (и обычный чат, и обсуждение канала).';
            } else if (parseMode === 'dialog') {
                modeHint.innerHTML = '🗣️ <b>Диалог для имитации:</b> собираем текст сообщений с информацией об авторах. После парсинга можно импортировать диалог в группу для прогрева — аккаунты будут воспроизводить чужое общение.';
            } else if (parseMode === 'topics') {
                modeHint.textContent = 'По темам: для форум-групп. Укажите ссылку для вступления (invite/@/ID). Для приватных групп t.me/c/... не подходит — нужен t.me/+...';
            } else if (parseMode === 'single_topic') {
                modeHint.textContent = '🎯 Две ссылки: сверху — группа (invite, @username или ID из «Мои группы»), ниже — топик t.me/c/.../ID. Так же, как в боте.';
            } else if (parseMode === 'ai_parse') {
                const sourceType = document.getElementById('parserSourceType')?.value || 'group';
                if (sourceType === 'channel') {
                    modeHint.textContent = '🤖 ИИ анализирует комментарии под постами канала. Видит текст поста (реклама/новость) и комментарий. Пост: t.me/channel/ID — или оставьте пустым для всех постов.';
                } else {
                    modeHint.textContent = '🤖 ИИ читает группу, форум-топик или ветку. Объём задаёт период или лимит сообщений. Топик: t.me/amnezia_vpn/830436';
                }
            } else if (parseMode === 'comments') {
                modeHint.textContent = 'Комментарии: только ответы под постами (reply). Работает для каналов с обсуждением и для групп, где пишут в комментариях к постам.';
            }
        }

        let _parserRangeType = 'limit';
        let _parserPeriodDays = 0;

        function parserRangeTypeChanged(type) {
            _parserRangeType = type || 'limit';
            _parserPeriodDays = 0;
            document.getElementById('parserLimitBlock').style.display  = type === 'limit'  ? 'block' : 'none';
            document.getElementById('parserPeriodBlock').style.display = type === 'period' ? 'block' : 'none';
            document.getElementById('parserDateBlock').style.display   = type === 'date'   ? 'block' : 'none';
            // Обновляем стили кнопок
            ['limit','period','date'].forEach(t => {
                const btn = document.getElementById('parserRangeBtn_' + t);
                if (!btn) return;
                if (t === type) {
                    btn.style.background = 'var(--primary)';
                    btn.style.color = '#000';
                    btn.style.borderColor = 'var(--primary)';
                    btn.style.fontWeight = '600';
                } else {
                    btn.style.background = 'transparent';
                    btn.style.color = 'var(--text-secondary)';
                    btn.style.borderColor = 'var(--border)';
                    btn.style.fontWeight = 'normal';
                }
            });
            // Сбрасываем активный пресет
            document.querySelectorAll('.parser-period-btn').forEach(b => {
                b.style.background = 'var(--bg-dark)';
                b.style.borderColor = 'var(--border)';
                b.style.color = 'var(--text)';
            });
        }

        function parserSetPeriod(days) {
            parserRangeTypeChanged('period');
            _parserPeriodDays = days;
            const now = new Date();
            const from = new Date(now);
            from.setDate(from.getDate() - days);
            from.setHours(0, 0, 0, 0);
            const fmt = d => d.toLocaleDateString('ru-RU', {day:'2-digit',month:'2-digit',year:'numeric'});
            document.getElementById('parserPeriodPreview').textContent =
                'с ' + fmt(from) + ' по ' + fmt(now) + ' (включительно)';
            // Подсвечиваем активный пресет
            document.querySelectorAll('.parser-period-btn').forEach(b => {
                const match = b.getAttribute('onclick') && b.getAttribute('onclick').includes('(' + days + ')');
                b.style.background   = match ? 'var(--primary)' : 'var(--bg-dark)';
                b.style.color        = match ? '#000' : 'var(--text)';
                b.style.borderColor  = match ? 'var(--primary)' : 'var(--border)';
            });
        }

        async function createAndStartParserJob() {
            if (!parserModalSelectedId) return;
            const groupLink = document.getElementById('parserGroupInput').value.trim();
            const topicLink = (document.getElementById('parserTopicLinkInput')?.value || '').trim();
            const aiPrompt = (document.getElementById('parserAiPromptInput')?.value || '').trim();
            const errorEl = document.getElementById('parserModalError');

            const sourceType = document.getElementById('parserSourceType').value;
            const parseMode = document.getElementById('parserParseMode').value;

            if (!groupLink) {
                if (parseMode === 'ai_parse' && sourceType === 'channel') {
                    errorEl.textContent = 'Укажите ссылку на канал (@channel или t.me/channel)';
                } else if (parseMode === 'single_topic' || parseMode === 'ai_parse') {
                    errorEl.textContent = 'Укажите ссылку на группу (invite, @username или ID)';
                } else {
                    errorEl.textContent = 'Введите ссылку на группу / канал';
                }
                return;
            }
            if (parseMode === 'single_topic' && !topicLink) {
                errorEl.textContent = 'Укажите ссылку на топик (t.me/c/.../ID)';
                return;
            }
            if (parseMode === 'ai_parse' && aiPrompt.length < 10) {
                errorEl.textContent = 'Опишите в промпте, кого искать в чате (минимум 10 символов)';
                return;
            }
            errorEl.textContent = '';
            const excludeBots = document.getElementById('parserExcludeBots').checked;
            const excludeAdmins = document.getElementById('parserExcludeAdmins').checked;
            const activityFilterRaw = document.getElementById('parserActivityFilter').value;
            const activityFilter = parseMode === 'members' ? activityFilterRaw : 'all';
            const delay = parseFloat(document.getElementById('parserDelayInput').value) || 3;
            const useProxy = document.getElementById('parserUseProxy').checked;
            const autoProxySwitch = useProxy ? document.getElementById('parserAutoProxySwitch').checked : false;

            // Date range for messages mode
            let limit = 0;
            let dateFrom = null;
            let dateTo = null;
            
            if (parseMode === 'messages' || parseMode === 'comments' || parseMode === 'topics' || parseMode === 'single_topic' || parseMode === 'ai_parse') {
                if (_parserRangeType === 'limit') {
                    limit = parseInt(document.getElementById('parserLimitInput').value) || 0;
                } else if (_parserRangeType === 'period') {
                    if (_parserPeriodDays <= 0) {
                        errorEl.textContent = 'Выбери период: 7, 30 или 90 дней';
                        return;
                    }
                    const now = new Date();
                    const from = new Date(now);
                    from.setDate(from.getDate() - _parserPeriodDays);
                    from.setHours(0, 0, 0, 0);
                    const to = new Date(now);
                    to.setHours(23, 59, 59, 999);
                    dateFrom = from.toISOString();
                    dateTo = to.toISOString();
                } else if (_parserRangeType === 'date') {
                    const dfVal = document.getElementById('parserDateFrom').value;
                    const dtVal = document.getElementById('parserDateTo').value;
                    if (dfVal) dateFrom = new Date(dfVal).toISOString();
                    if (dtVal) dateTo = new Date(dtVal + 'T23:59:59').toISOString();
                }
            }

            try {
                const createRes = await fetch(`${API_URL}/parser/jobs`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        account_id: parserModalSelectedId,
                        group_link: groupLink,
                        limit_messages: limit,
                        delay_seconds: delay,
                        source_type: sourceType,
                        parse_mode: parseMode,
                        date_from: dateFrom,
                        date_to: dateTo,
                        exclude_bots: excludeBots,
                        exclude_admins: excludeAdmins,
                        activity_filter: activityFilter,
                        use_proxy: useProxy,
                        auto_proxy_switch: autoProxySwitch,
                        topic_link: (parseMode === 'single_topic' || (parseMode === 'ai_parse' && topicLink)) ? topicLink : null,
                        ai_prompt: parseMode === 'ai_parse' ? aiPrompt : null
                    })
                });
                const createData = await createRes.json();
                if (!createRes.ok) {
                    errorEl.textContent = createData.detail || 'Ошибка создания задачи';
                    return;
                }

                const startRes = await fetch(`${API_URL}/parser/jobs/${createData.job_id}/start`, {
                    method: 'POST',
                });
                if (!startRes.ok) {
                    const sd = await startRes.json();
                    errorEl.textContent = sd.detail || 'Ошибка запуска';
                    return;
                }

                closeParserModal();
                await loadParserJobs();
            } catch (err) {
                errorEl.textContent = 'Ошибка: ' + err.message;
            }
        }

        async function startParserJob(jobId, opts = {}) {
            try {
                const params = new URLSearchParams();
                if (opts.resume) params.set('resume', 'true');
                if (opts.restart) params.set('restart', 'true');
                const qs = params.toString();
                const res = await fetch(`${API_URL}/parser/jobs/${jobId}/start${qs ? `?${qs}` : ''}`, {
                    method: 'POST',
                });
                if (!res.ok) {
                    const data = await res.json();
                    ugAlert(data.detail || 'Ошибка запуска', 'error');
                }
                await loadParserJobs();
            } catch (err) {
                ugAlert('Ошибка: ' + err.message, 'error');
            }
        }

        async function resumeParserJob(jobId) {
            await startParserJob(jobId, { resume: true });
        }

        async function restartParserJob(jobId) {
            if (!await ugConfirm('Начать заново? Собранные результаты будут удалены.')) return;
            await startParserJob(jobId, { restart: true });
        }

        async function stopParserJob(jobId) {
            if (!await ugConfirm('Остановить парсинг? Собранные данные будут сохранены.')) return;
            try {
                const res = await fetch(`${API_URL}/parser/jobs/${jobId}/stop`, {
                    method: 'POST',
                });
                if (!res.ok) {
                    const data = await res.json();
                    ugAlert(data.detail || 'Ошибка остановки', 'error');
                }
                await loadParserJobs();
            } catch (err) {
                ugAlert('Ошибка: ' + err.message, 'error');
            }
        }

        async function deleteParserJob(jobId) {
            if (!await ugConfirm('Удалить задачу и результаты?')) return;
            try {
                const res = await fetch(`${API_URL}/parser/jobs/${jobId}`, {
                    method: 'DELETE',
                });
                if (!res.ok) {
                    const data = await res.json();
                    ugAlert(data.detail || 'Ошибка удаления', 'error');
                }
                await loadParserJobs();
            } catch (err) {
                ugAlert('Ошибка: ' + err.message, 'error');
            }
        }

        // ===== Мои группы =====
        async function openMyGroupsModal() {
            if (!parserModalSelectedId) {
                ugAlert('Сначала выберите аккаунт', 'warning');
                return;
            }

            document.getElementById('myGroupsModal').classList.add('show');
            document.getElementById('myGroupsLoading').style.display = 'block';
            document.getElementById('myGroupsLoading').innerHTML = '<div class="spinner" style="margin:0 auto 16px;width:36px;height:36px;border:3px solid var(--border);border-top-color:var(--primary);border-radius:50%;animation:spin 0.8s linear infinite;"></div><div style="font-size:0.95rem;color:var(--text);">Подключение к аккаунту...</div><div style="font-size:0.8rem;margin-top:6px;color:var(--text-secondary);">Не закрывайте окно</div>';
            document.getElementById('myGroupsList').style.display = 'none';
            document.getElementById('myGroupsList').innerHTML = '';

            try {
                const formData = new FormData();
                formData.append('account_id', parserModalSelectedId);
                const res = await fetch(`${API_URL}/parser/my-groups`, {
                    method: 'POST',
                    body: formData
                });
                const raw = await res.text();
                let data = null;
                try {
                    data = raw ? JSON.parse(raw) : {};
                } catch {
                    data = null;
                }
                if (!res.ok) {
                    const detail = (data && (data.detail || data.error))
                        ? (data.detail || data.error)
                        : `HTTP ${res.status}`;
                    throw new Error(detail);
                }
                if (!data) {
                    throw new Error('Сервер вернул некорректный ответ');
                }
                renderMyGroups(data.groups || []);
            } catch (err) {
                document.getElementById('myGroupsLoading').innerHTML = `<span style="color:var(--error);">❌ ${escapeHtml(err.message)}</span>`;
            }
        }

        function renderMyGroups(groups) {
            document.getElementById('myGroupsLoading').style.display = 'none';
            const container = document.getElementById('myGroupsList');
            container.style.display = 'block';

            if (!groups.length) {
                container.innerHTML = '<p style="color:var(--text-secondary);text-align:center;padding:20px;">Аккаунт не состоит ни в одной группе</p>';
                return;
            }

            const typeMap = { group: 'группа', supergroup: 'супергруппа', channel: 'канал' };
            container.innerHTML = `
                <table style="width:100%;border-collapse:collapse;font-size:0.85rem;">
                    <thead>
                        <tr style="border-bottom:1px solid var(--border);">
                            <th style="text-align:left;padding:8px;">Название</th>
                            <th style="text-align:left;padding:8px;">Ссылка</th>
                            <th style="text-align:left;padding:8px;">Тип</th>
                            <th style="text-align:right;padding:8px;">Участников</th>
                            <th style="text-align:right;padding:8px;">ID</th>
                        </tr>
                    </thead>
                    <tbody>
                        ${groups.map(g => {
                            const link = g.username ? `https://t.me/${g.username}` : '';
                            const linkHtml = g.username 
                                ? `<span style="font-family:monospace;color:var(--primary);cursor:pointer;user-select:all;background:var(--bg-dark);padding:1px 4px;border-radius:3px;font-size:0.8rem;" onclick="event.stopPropagation();copyText('https://t.me/${g.username}',this)" title="Клик — скопировать">@${g.username}</span>` 
                                : '<span style="color:var(--text-secondary);font-size:0.75rem;">—</span>';
                            const pick = g.username ? `https://t.me/${g.username}` : '';
                            return `
                            <tr style="border-bottom:1px solid var(--border);cursor:pointer;" onmouseover="this.style.background='var(--bg-hover)'" onmouseout="this.style.background=''" onclick="selectGroup('${pick || g.id}')">
                                <td style="padding:8px;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${escapeHtml(g.title) || 'Без названия'}</td>
                                <td style="padding:8px;">${linkHtml}</td>
                                <td style="padding:8px;color:var(--text-secondary);">${typeMap[g.type] || escapeHtml(g.type)}</td>
                                <td style="padding:8px;text-align:right;">${g.members || '?'}</td>
                                <td style="padding:8px;text-align:right;font-family:monospace;font-size:0.8rem;">${g.id}</td>
                            </tr>`;
                        }).join('')}
                    </tbody>
                </table>
                <p style="text-align:center;color:var(--text-secondary);font-size:0.8rem;margin-top:10px;">Найдено ${groups.length} групп/каналов. Кликните для выбора.</p>
            `;
        }

        function selectGroup(groupId) {
            document.getElementById('parserGroupInput').value = groupId;
            closeMyGroupsModal();
        }

        function closeMyGroupsModal() {
            document.getElementById('myGroupsModal').classList.remove('show');
        }

        // ===== Результаты парсинга =====
        function _fmtParserMsgs(msgs) {
            if (!Array.isArray(msgs) || !msgs.length) return '';
            const fmtDate = (d) => {
                const m = String(d || '').match(/(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})/);
                return m ? `${m[3]}.${m[2]} ${m[4]}:${m[5]}` : '';
            };
            const lines = msgs.slice(0, 6).map(m => {
                const t = escapeHtml(String(m.text || '').slice(0, 160));
                const d = fmtDate(m.date);
                return `<div style="margin-top:3px;opacity:.85;">${d ? '🕒 ' + d + ' — ' : ''}«${t}»</div>`;
            }).join('');
            return `<div style="margin-top:5px;border-top:1px dashed var(--border);padding-top:4px;font-size:0.72rem;">${lines}</div>`;
        }

        async function openParserResults(jobId) {
            currentParserResultJobId = jobId;
            window.currentParserResultJobId = jobId;
            document.getElementById('parserResultsModal').classList.add('show');
            document.body.classList.add('ug-bc-modal-open');
            document.getElementById('parserResultsStats').innerHTML = 'Загрузка...';
            document.getElementById('parserResultsTable').innerHTML = '';

            try {
                // Загружаем детали задачи
                const jobRes = await fetch(`${API_URL}/parser/jobs/${jobId}`, {
                });
                if (!jobRes.ok) throw new Error('Ошибка');
                const job = await jobRes.json();

                // Заголовок с названием и ссылкой
                const groupLink = job.group_link || '';
                const linkDisplay = groupLink ? `<span style="font-family:monospace;font-size:0.85rem;color:var(--primary);cursor:pointer;user-select:all;background:var(--bg-dark);padding:2px 6px;border-radius:4px;margin-left:8px;" onclick="copyText('${escapeHtml(groupLink)}',this)">${escapeHtml(groupLink)}</span>` : '';
                document.getElementById('parserResultsTitle').innerHTML = `${escapeHtml(job.group_title || job.group_link)}${linkDisplay}`;

                document.getElementById('parserResultsStats').innerHTML = `
                    <div style="padding:10px 16px;background:var(--bg-dark);border-radius:8px;border:1px solid var(--border);">
                        <div style="font-size:1.2rem;font-weight:700;color:var(--text);">${job.total_users}</div>
                        <div style="font-size:0.75rem;color:var(--text-secondary);">Всего юзеров</div>
                    </div>
                    <div style="padding:10px 16px;background:var(--bg-dark);border-radius:8px;border:1px solid var(--border);">
                        <div style="font-size:1.2rem;font-weight:700;color:var(--primary);">${job.users_with_username}</div>
                        <div style="font-size:0.75rem;color:var(--text-secondary);">С @username</div>
                    </div>
                    <div style="padding:10px 16px;background:var(--bg-dark);border-radius:8px;border:1px solid var(--border);">
                        <div style="font-size:1.2rem;font-weight:700;color:var(--text);">${job.total_messages}</div>
                        <div style="font-size:0.75rem;color:var(--text-secondary);">Сообщений</div>
                    </div>
                `;

                // Загружаем первую страницу результатов
                const resultsRes = await fetch(`${API_URL}/parser/jobs/${jobId}/results?page=1&per_page=100`, {
                });
                if (!resultsRes.ok) throw new Error('Ошибка загрузки');
                const resultsData = await resultsRes.json();
                const results = resultsData.results || [];

                if (!results.length) {
                    document.getElementById('parserResultsTable').innerHTML = '<p style="color:var(--text-secondary);text-align:center;padding:20px;">Нет результатов</p>';
                    return;
                }

                const showBio = results.some(r => r.profile_bio);
                const showAiReason = job.parse_mode === 'ai_parse' || results.some(r => r.ai_reason);
                document.getElementById('parserResultsTable').innerHTML = `
                    <table style="width:100%;border-collapse:collapse;font-size:0.85rem;">
                        <thead>
                            <tr style="border-bottom:1px solid var(--border);position:sticky;top:0;background:var(--card-bg);">
                                <th style="text-align:left;padding:6px;">#</th>
                                <th style="text-align:left;padding:6px;">Username</th>
                                <th style="text-align:left;padding:6px;">Имя</th>
                                ${showBio ? '<th style="text-align:left;padding:6px;">Telegram bio</th>' : ''}
                                ${showAiReason ? '<th style="text-align:left;padding:6px;">Почему подходит</th>' : ''}
                                <th style="text-align:right;padding:6px;">Совп.</th>
                            </tr>
                        </thead>
                        <tbody>
                            ${results.map((r, i) => `
                                <tr style="border-bottom:1px solid var(--border);">
                                    <td style="padding:5px 6px;color:var(--text-secondary);font-size:0.75rem;">${i + 1}</td>
                                    <td style="padding:5px 6px;">${r.username 
                                        ? `<span style="font-family:monospace;color:var(--primary);cursor:pointer;user-select:all;background:var(--bg-dark);padding:1px 4px;border-radius:3px;" onclick="copyText('@${r.username}',this)" title="Клик — скопировать">@${r.username}</span>` 
                                        : `<span style="font-family:monospace;color:var(--text-secondary);">[${r.tg_user_id}]</span>`}</td>
                                    <td style="padding:5px 6px;">${escapeHtml(r.first_name || '')} ${escapeHtml(r.last_name || '')}</td>
                                    ${showBio ? `<td style="padding:5px 6px;font-size:0.78rem;color:var(--text-secondary);max-width:220px;">${escapeHtml(r.profile_bio || '—')}</td>` : ''}
                                    ${showAiReason ? `<td style="padding:5px 6px;font-size:0.78rem;color:var(--text-secondary);max-width:300px;">${escapeHtml(r.ai_reason || '—')}${_fmtParserMsgs(r.ai_messages)}</td>` : ''}
                                    <td style="padding:5px 6px;text-align:right;">${r.msg_count}</td>
                                </tr>
                            `).join('')}
                        </tbody>
                    </table>
                    ${resultsData.total > 100 ? `<p style="text-align:center;color:var(--text-secondary);font-size:0.8rem;margin-top:8px;">Показано 100 из ${resultsData.total}. Для полного списка скачайте файл.</p>` : ''}
                `;
            } catch (err) {
                document.getElementById('parserResultsStats').innerHTML = `<span style="color:var(--error);">❌ ${escapeHtml(err.message)}</span>`;
            }
        }

        function closeParserResultsModal() {
            document.getElementById('parserResultsModal')?.classList.remove('show');
            if (!document.querySelector('#ugParserModals .modal-overlay.show')) {
                document.body.classList.remove('ug-bc-modal-open');
            }
        }

        async function downloadParserResults(jobId, fmt) {
            if (!jobId) return;
            try {
                const res = await fetch(`${API_URL}/parser/jobs/${jobId}/download/${fmt}`, {
                });
                if (!res.ok) {
                    let msg = 'Ошибка скачивания';
                    try {
                        const err = await res.json();
                        msg = err.detail || msg;
                    } catch (_) {}
                    ugAlert(msg, 'error');
                    return;
                }
                const blob = await res.blob();
                const disposition = res.headers.get('Content-Disposition') || '';
                const match = disposition.match(/filename="?([^"]+)"?/);
                const filename = match ? match[1] : `parser_results.${fmt === 'csv' ? 'csv' : 'txt'}`;
                const a = document.createElement('a');
                a.href = URL.createObjectURL(blob);
                a.download = filename;
                a.click();
                URL.revokeObjectURL(a.href);
            } catch (err) {
                ugAlert('Ошибка: ' + err.message, 'error');
            }
        }

        async function copyParserUsernames(jobId) {
            if (!jobId) return;
            try {
                const res = await fetch(`${API_URL}/parser/jobs/${jobId}/download/usernames`);
                if (!res.ok) { ugAlert('Ошибка загрузки', 'error'); return; }
                const text = await res.text();
                await navigator.clipboard.writeText(text);
                const count = text.split('\n').filter(l => l.trim()).length;
                ugAlert(`Скопировано ${count} юзернеймов`, 'success');
            } catch (err) {
                ugAlert('Ошибка: ' + err.message, 'error');
            }
        }

function initParserUi() {
  const btn = document.querySelector('#tab-parsing .glow-btn-create');
  if (btn && !btn.dataset.parserBound) {
    btn.dataset.parserBound = '1';
    btn.addEventListener('click', (e) => {
      e.preventDefault();
      openCreateParserModal();
    });
  }
  if (!document.body.dataset.parserEscBound) {
    document.body.dataset.parserEscBound = '1';
    document.addEventListener('keydown', (e) => {
      if (e.key !== 'Escape') return;
      if (document.getElementById('parserResultsModal')?.classList.contains('show')) {
        closeParserResultsModal();
      } else if (document.getElementById('createParserModal')?.classList.contains('show')) {
        closeParserModal();
      } else if (document.getElementById('myGroupsModal')?.classList.contains('show')) {
        closeMyGroupsModal();
      }
    });
  }
}

Object.assign(window, {
  loadParserJobs, startParserJobsRefresh, openCreateParserModal, closeParserModal,
  parserModalNextStep, parserModalPrevStep, parserSourceTypeChanged, parserParseModeChanged,
  parserRangeTypeChanged, parserSetPeriod, createAndStartParserJob,
  startParserJob, resumeParserJob, restartParserJob, stopParserJob, deleteParserJob, openMyGroupsModal, closeMyGroupsModal,
  selectGroup, openParserResults, closeParserResultsModal, downloadParserResults,
  copyParserUsernames, initParserUi,
});

if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initParserUi);
} else {
  initParserUi();
}
})();