<?php

error_reporting(E_ALL); ini_set('display_errors', 1);
/**
 * audit_check.php — аудит готовности веб-страницы
 * Проверка по ссылке из поля ввода, ручное управление статусами,
 * добавление пунктов, точка остановки наверху, тёмная тема.
 *
 * Данные хранятся в JSON-файле рядом со скриптом.
 * Запуск: php -S localhost:8000 и открыть http://localhost:8000/audit_check.php
 */

class WebPageAudit {
    private string $url;
    private string $dataFile;
    private ?string $pageContent = null;
    private array $auditData;

    // Палитра с сайта-источника (тёмная тема + оранжевый акцент)
    private const COLORS = [
        'bg'        => '#121212',
        'surface'   => '#1e1e1e',
        'surface2'  => '#2a2a2a',
        'border'    => '#3a3a3a',
        'text'      => '#e8e8e8',
        'muted'     => '#9a9a9a',
        'accent'    => '#ff7a00', // оранжевый CTA сайта
        'accent2'   => '#ffb300',
        'success'   => '#2ecc71',
        'danger'    => '#e74c3c',
        'warn'      => '#f1c40f',
        'info'      => '#3498db',
    ];

    public function __construct(string $url = '') {
        $this->url = $url;
        $this->dataFile = __DIR__ . '/audit_status.json';
        $this->loadData();
    }

    private function loadData(): void {
        if (file_exists($this->dataFile)) {
            $json = file_get_contents($this->dataFile);
            $decoded = json_decode($json, true);
            if (is_array($decoded) && isset($decoded['items'])) {
                $this->auditData = $decoded;
                return;
            }
        }
        $this->auditData = $this->getDefaultAuditData();
        $this->saveData();
    }

    private function saveData(): void {
        file_put_contents(
            $this->dataFile,
            json_encode($this->auditData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
        );
    }

    private function getDefaultAuditData(): array {
        return [
            'url'          => '',
            'progress'     => 0,
            'total_items'  => 0,
            'ready_items'  => 0,
            'stop_point'   => '—',
            'stop_item'    => '—',
            'next_id'      => 1,
            'items'        => [],
        ];
    }

    /**
     * Базовый чек-лист (этапы + пункты).
     * Этапы: 1. Контент и дизайн, 2. Техническая часть и SEO,
     * 3. Функциональность и аналитика, 4. Хостинг и деплой, Пост-релиз (24ч)
     */
    private function getDefaultChecklist(): array {
        return [
            ['stage' => '1. Контент и дизайн', 'name' => 'Орфография и пунктуация', 'status' => 'fail', 'note' => 'Требуется вычитка текста.'],
            ['stage' => '1. Контент и дизайн', 'name' => 'Единообразие стиля', 'status' => 'fail', 'note' => 'Проверить визуально.'],
            ['stage' => '1. Контент и дизайн', 'name' => 'Адаптивность вёрстки', 'status' => 'fail', 'note' => 'Проверка на устройствах.'],
            ['stage' => '1. Контент и дизайн', 'name' => 'Кроссбраузерность', 'status' => 'fail', 'note' => 'Прогон в 5+ браузерах.'],
            ['stage' => '1. Контент и дизайн', 'name' => 'Изображения (WebP/AVIF, alt)', 'status' => 'fail', 'note' => 'Проверить форматы и alt.'],
            ['stage' => '1. Контент и дизайн', 'name' => 'Читаемость текста (WCAG)', 'status' => 'fail', 'note' => 'Проверить контраст.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Скорость загрузки (PageSpeed > 90)', 'status' => 'fail', 'note' => 'Замерить PageSpeed.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Метатеги (title, description)', 'status' => 'fail', 'note' => 'Проверить в <head>.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Open Graph / Twitter Card', 'status' => 'fail', 'note' => 'Проверить теги.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Семантическая вёрстка', 'status' => 'fail', 'note' => 'header, main, footer.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Иерархия заголовков (H1→H3)', 'status' => 'fail', 'note' => 'Проверить структуру.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Favicon (ico/png/svg)', 'status' => 'fail', 'note' => 'Проверить link rel=icon.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'SSL-сертификат (HTTPS)', 'status' => 'fail', 'note' => 'Проверить https.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Редирект с HTTP', 'status' => 'fail', 'note' => 'curl -I http://...'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Каноникал (canonical)', 'status' => 'fail', 'note' => 'Проверить тег.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Sitemap.xml', 'status' => 'fail', 'note' => 'Проверить наличие.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Robots.txt', 'status' => 'fail', 'note' => 'Проверить наличие.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Страница 404', 'status' => 'fail', 'note' => 'Тестовый запрос.'],
            ['stage' => '2. Техническая часть и SEO', 'name' => 'Валидность кода (W3C)', 'status' => 'fail', 'note' => 'validator.w3.org.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Формы (валидация, маска)', 'status' => 'fail', 'note' => 'Проверить формы.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Интеграции (CRM, Telegram)', 'status' => 'fail', 'note' => 'Тестовая отправка.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Цели аналитики (Метрика/GA4)', 'status' => 'fail', 'note' => 'Проверить счётчики.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Ссылки (якоря, rel)', 'status' => 'fail', 'note' => 'Проверить ссылки.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Кнопки CTA (глаголы)', 'status' => 'fail', 'note' => 'Проверить кнопки.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Политика конфиденциальности', 'status' => 'fail', 'note' => 'Ссылка и чекбокс согласия.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Юридическая информация (ОГРН/ИНН)', 'status' => 'fail', 'note' => 'Проверить в футере.'],
            ['stage' => '3. Функциональность и аналитика', 'name' => 'Доступность (Accessibility, ARIA)', 'status' => 'fail', 'note' => 'ARIA и skip-links.'],
            ['stage' => '4. Хостинг и деплой', 'name' => 'Резервная копия', 'status' => 'fail', 'note' => 'Уточнить у разработчика.'],
            ['stage' => '4. Хостинг и деплой', 'name' => 'Доменная почта (SPF/DKIM/DMARC)', 'status' => 'fail', 'note' => 'Проверить DNS.'],
            ['stage' => '4. Хостинг и деплой', 'name' => 'DNS-записи (A/Proxy)', 'status' => 'fail', 'note' => 'Проверить DNS.'],
            ['stage' => '4. Хостинг и деплой', 'name' => 'Режим обслуживания', 'status' => 'fail', 'note' => 'Сайт доступен.'],
            ['stage' => '4. Хостинг и деплой', 'name' => 'Логи сервера', 'status' => 'fail', 'note' => 'Запросить у хостинга.'],
            ['stage' => '4. Хостинг и деплой', 'name' => 'Бэкап-план (Rollback 15 мин)', 'status' => 'fail', 'note' => 'Проверить инструкции отката.'],
            ['stage' => 'Пост-релиз (24ч)', 'name' => 'Посещаемость роботов (Вебмастер)', 'status' => 'fail', 'note' => 'Проверить после релиза.'],
            ['stage' => 'Пост-релиз (24ч)', 'name' => 'Тест заявок с продакшна', 'status' => 'fail', 'note' => 'Проверить после релиза.'],
            ['stage' => 'Пост-релиз (24ч)', 'name' => 'Проверка аналитики (ошибки JS)', 'status' => 'fail', 'note' => 'Проверить после релиза.'],
            ['stage' => 'Пост-релиз (24ч)', 'name' => 'Контроль скорости (через 1 час)', 'status' => 'fail', 'note' => 'Проверить после релиза.'],
        ];
    }

    /** Пересоздаёт чек-лист (используется при первом запуске / смене URL) */
    private function rebuildChecklist(): void {
        $items = [];
        $id = 1;
        foreach ($this->getDefaultChecklist() as $row) {
            $items[] = [
                'id'     => (string)$id,
                'stage'  => $row['stage'],
                'name'   => $row['name'],
                'status' => $row['status'],
                'note'   => $row['note'],
            ];
            $id++;
        }
        $this->auditData['items'] = $items;
        $this->auditData['next_id'] = $id;
        $this->auditData['url'] = $this->url;
        $this->updateProgress();
        $this->findStopPoint();
        $this->saveData();
    }

    /** Загрузка страницы и простейшие автоматические проверки */
    public function fetchPageContent(): bool {
        if ($this->url === '') {
            return false;
        }
        $context = stream_context_create([
            'http' => [
                'timeout' => 10,
                'user_agent' => 'Mozilla/5.0 (WebPageAudit/1.0)',
                'ignore_errors' => true,
            ],
            'ssl' => ['verify_peer' => false, 'verify_peer_name' => false],
        ]);
        $content = @file_get_contents($this->url, false, $context);
        if ($content === false) {
            return false;
        }
        $this->pageContent = $content;
        return true;
    }

    /** Автоматическая проверка пунктов по загруженному HTML */
    public function autoCheck(): void {
        if ($this->pageContent === null) {
            return;
        }
        $html = $this->pageContent;

        $checks = [
            'Метатеги (title, description)' => (bool)preg_match('/<title>[^<]+<\/title>/i', $html),
            'Open Graph / Twitter Card'     => (bool)preg_match('/property=["\']og:/i', $html),
            'Семантическая вёрстка'         => (bool)preg_match('/<(header|main|footer|nav)[\s>]/i', $html),
            'Favicon (ico/png/svg)'         => (bool)preg_match('/rel=["\'](?:shortcut )?icon["\']/i', $html),
            'SSL-сертификат (HTTPS)'        => str_starts_with($this->url, 'https://'),
            'Каноникал (canonical)'         => (bool)preg_match('/rel=["\']canonical["\']/i', $html),
            'Формы (валидация, маска)'      => (bool)preg_match('/<form[\s>]/i', $html),
            'Кнопки CTA (глаголы)'          => (bool)preg_match('/<button[\s>]/i', $html),
            'Политика конфиденциальности'   => (bool)preg_match('/политик[аи]\s+конфиденциальности/iu', $html),
            'Доступность (Accessibility, ARIA)' => (bool)preg_match('/aria-[a-z]+=/i', $html),
        ];

        foreach ($this->auditData['items'] as &$item) {
            foreach ($checks as $name => $ok) {
                if ($item['name'] === $name) {
                    if ($ok && $item['status'] !== 'ready') {
                        $item['status'] = 'ready';
                        $item['note'] = 'Автопроверка: найдено в HTML.';
                    } elseif (!$ok && $item['status'] === 'ready') {
                        $item['status'] = 'fail';
                        $item['note'] = 'Автопроверка: не найдено в HTML.';
                    }
                    break;
                }
            }
        }
        unset($item);

        $this->updateProgress();
        $this->findStopPoint();
        $this->saveData();
    }

    public function updateProgress(): void {
        $total = count($this->auditData['items']);
        $ready = 0;
        foreach ($this->auditData['items'] as $item) {
            if ($item['status'] === 'ready') {
                $ready++;
            }
        }
        $this->auditData['total_items'] = $total;
        $this->auditData['ready_items'] = $ready;
        $this->auditData['progress'] = $total > 0 ? (int)round(($ready / $total) * 100) : 0;
    }

    /** Точка остановки: первый неготовый (fail/warn) пункт по порядку */
    public function findStopPoint(): void {
        $stopStage = 'Готово к запуску';
        $stopItem = '—';
        foreach ($this->auditData['items'] as $item) {
            if ($item['status'] !== 'ready') {
                $stopStage = $item['stage'];
                $stopItem = $item['name'];
                break;
            }
        }
        $this->auditData['stop_point'] = $stopStage;
        $this->auditData['stop_item'] = $stopItem;
    }

    /** Обработка POST-действий */
    public function handleActions(): void {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            return;
        }
        $action = $_POST['action'] ?? '';

        // 0. Проверка по ссылке (кнопка "Проверить")
        if ($action === 'check_url') {
            $this->url = trim($_POST['url'] ?? '');
            $this->auditData['url'] = $this->url;
            if ($this->url !== '' && $this->fetchPageContent()) {
                if (empty($this->auditData['items'])) {
                    $this->rebuildChecklist();
                }
                $this->autoCheck();
            }
            $this->saveData();
            $this->redirect();
        }

        // 1. Ручное изменение статуса
        if ($action === 'update_status') {
            $id = $_POST['item_id'] ?? '';
            $status = $_POST['status'] ?? 'fail';
            if (!in_array($status, ['ready', 'fail', 'warn'], true)) {
                $status = 'fail';
            }
            foreach ($this->auditData['items'] as &$item) {
                if ($item['id'] === $id) {
                    $item['status'] = $status;
                    break;
                }
            }
            unset($item);
            $this->updateProgress();
            $this->findStopPoint();
            $this->saveData();
            $this->redirect();
        }

        // 2. Пересчёт прогресса
        if ($action === 'recalc') {
            $this->updateProgress();
            $this->findStopPoint();
            $this->saveData();
            $this->redirect();
        }

        // Добавление нового пункта
        if ($action === 'add_item') {
            $name = trim($_POST['name'] ?? '');
            $stage = trim($_POST['stage'] ?? '1. Контент и дизайн');
            $note = trim($_POST['note'] ?? '');
            if ($name !== '') {
                $id = (string)($this->auditData['next_id'] ?? (count($this->auditData['items']) + 1));
                $this->auditData['items'][] = [
                    'id'     => $id,
                    'stage'  => $stage,
                    'name'   => $name,
                    'status' => 'fail',
                    'note'   => $note,
                ];
                $this->auditData['next_id'] = (int)$id + 1;
                $this->updateProgress();
                $this->findStopPoint();
                $this->saveData();
            }
            $this->redirect();
        }

        // Удаление пункта (по желанию)
        if ($action === 'delete_item') {
            $id = $_POST['item_id'] ?? '';
            $this->auditData['items'] = array_values(array_filter(
                $this->auditData['items'],
                fn($it) => $it['id'] !== $id
            ));
            $this->updateProgress();
            $this->findStopPoint();
            $this->saveData();
            $this->redirect();
        }
    }

    private function redirect(): void {
        $self = strtok($_SERVER['REQUEST_URI'], '?');
        header('Location: ' . $self);
        exit;
    }

    private function statusLabel(string $status): string {
        return match ($status) {
            'ready' => '✅ Готово',
            'fail'  => '❌ Не готово',
            'warn'  => '⚠️ Пропущено',
            default => '❓',
        };
    }

    private function statusClass(string $status): string {
        return match ($status) {
            'ready' => 'st-ready',
            'fail'  => 'st-fail',
            'warn'  => 'st-warn',
            default => 'st-info',
        };
    }

    public function render(): void {
        $this->handleActions();
        $c = self::COLORS;
        ?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Аудит готовности страницы</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        :root {
            --bg: <?= $c['bg'] ?>;
            --surface: <?= $c['surface'] ?>;
            --surface2: <?= $c['surface2'] ?>;
            --border: <?= $c['border'] ?>;
            --text: <?= $c['text'] ?>;
            --muted: <?= $c['muted'] ?>;
            --accent: <?= $c['accent'] ?>;
            --accent2: <?= $c['accent2'] ?>;
            --success: <?= $c['success'] ?>;
            --danger: <?= $c['danger'] ?>;
            --warn: <?= $c['warn'] ?>;
            --info: <?= $c['info'] ?>;
        }
        body {
            background: var(--bg);
            color: var(--text);
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
        }
        .container-audit { max-width: 1200px; }
        a { color: var(--accent2); }
        a:hover { color: var(--accent); }

        .card-dark {
            background: var(--surface);
            border: 1px solid var(--border);
            border-radius: 12px;
        }
        .stop-point-box {
            background: linear-gradient(135deg, var(--surface2), var(--surface));
            border: 1px solid var(--accent);
            border-left: 6px solid var(--accent);
            border-radius: 12px;
            padding: 16px 20px;
            margin-bottom: 20px;
        }
        .stop-point-box h5 { color: var(--accent); margin-bottom: 8px; }
        .stop-point-box .sp-stage { font-size: 14px; color: var(--muted); }
        .stop-point-box .sp-item { font-size: 18px; font-weight: 700; color: var(--text); }

        .progress-custom { height: 18px; border-radius: 9px; background: var(--surface2); }
        .progress-custom .progress-bar {
            border-radius: 9px; font-size: 12px; font-weight: 700; color: #111;
        }
        .bg-ready { background: var(--success) !important; }
        .bg-mid { background: var(--accent2) !important; }
        .bg-low { background: var(--danger) !important; }

        .timeline-horizontal { position: relative; display: flex; justify-content: space-between;
            padding: 0 10px; margin: 24px 0 30px; }
        .timeline-horizontal::before {
            content: ''; position: absolute; height: 4px; background: var(--border);
            top: 22px; left: 30px; right: 30px; border-radius: 2px; z-index: 0;
        }
        .tl-step { position: relative; z-index: 1; text-align: center; flex: 1; }
        .tl-dot {
            width: 44px; height: 44px; border-radius: 50%; margin: 0 auto 8px;
            display: flex; align-items: center; justify-content: center;
            background: var(--surface2); border: 3px solid var(--border);
            color: var(--text); font-weight: 700; font-size: 15px;
            transition: all .2s;
        }
        .tl-step.done .tl-dot { background: var(--success); border-color: var(--success); color: #111; }
        .tl-step.active .tl-dot { background: var(--accent); border-color: var(--accent); color: #111; }
        .tl-step.fail .tl-dot { background: var(--danger); border-color: var(--danger); color: #fff; }
        .tl-label { font-size: 12px; color: var(--muted); font-weight: 600; }

        .table-dark-audit { color: var(--text); }
        .table-dark-audit thead th {
            background: var(--surface2); color: var(--text); border-color: var(--border);
            text-transform: uppercase; font-size: 11px; letter-spacing: .5px;
        }
        .table-dark-audit td, .table-dark-audit th { border-color: var(--border); vertical-align: middle; }
        .table-dark-audit tbody tr:hover { background: rgba(255,122,0,.06); }
        .stage-row td {
            background: var(--surface2) !important; text-align: center;
        }
        .stage-badge {
            display: inline-block; padding: 4px 12px; border-radius: 999px;
            font-size: 11px; font-weight: 700; text-transform: uppercase;
            letter-spacing: .5px; background: var(--accent); color: #111;
        }

        .status-badge {
            display: inline-block; padding: 4px 10px; border-radius: 999px;
            font-size: 12px; font-weight: 700;
        }
        .st-ready { background: rgba(46,204,113,.18); color: var(--success); border: 1px solid var(--success); }
        .st-fail  { background: rgba(231,76,60,.18);  color: var(--danger);  border: 1px solid var(--danger); }
        .st-warn  { background: rgba(241,196,15,.18); color: var(--warn);    border: 1px solid var(--warn); }
        .st-info  { background: rgba(52,152,219,.18); color: var(--info);    border: 1px solid var(--info); }

        .form-control, .form-select, .input-group-text {
            background: var(--surface2); border-color: var(--border); color: var(--text);
        }
        .form-control:focus, .form-select:focus {
            background: var(--surface2); color: var(--text);
            border-color: var(--accent); box-shadow: 0 0 0 .2rem rgba(255,122,0,.25);
        }
        .form-control::placeholder { color: var(--muted); }
        .btn-accent { background: var(--accent); border-color: var(--accent); color: #111; font-weight: 700; }
        .btn-accent:hover { background: var(--accent2); border-color: var(--accent2); color: #111; }
        .btn-outline-light-audit { border: 1px solid var(--border); color: var(--text); }
        .btn-outline-light-audit:hover { background: var(--surface2); color: var(--text); }
        .btn-danger-audit { background: var(--danger); border-color: var(--danger); color: #fff; }

        .modal-content { background: var(--surface); color: var(--text); border: 1px solid var(--border); }
        .modal-header, .modal-footer { border-color: var(--border); }
        .btn-close { filter: invert(1); }

        .note-muted { color: var(--muted); font-size: 12px; }
        .action-select { min-width: 150px; }
        .item-name { font-weight: 600; }
        .hint { color: var(--muted); font-size: 13px; }
    </style>
</head>
<body>
<div class="container container-audit py-4">

    <!-- Заголовок и поле ввода URL -->
    <div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
        <h3 class="mb-0">Аудит готовности страницы</h3>
        <?php if (!empty($this->auditData['url'])): ?>
            <a href="<?= htmlspecialchars($this->auditData['url']) ?>" target="_blank" class="hint">
                <?= htmlspecialchars($this->auditData['url']) ?> ↗
            </a>
        <?php endif; ?>
    </div>

    <form method="POST" class="card-dark p-3 mb-3">
        <input type="hidden" name="action" value="check_url">
        <label class="form-label hint mb-1">Ссылка на проверяемую страницу</label>
        <div class="input-group">
            <input type="url" name="url" class="form-control"
                   placeholder="https://experiments.autobleskdmd.ru/update/index.html"
                   value="<?= htmlspecialchars($_POST['url'] ?? $this->auditData['url'] ?? '') ?>" required>
            <button class="btn btn-accent" type="submit">Проверить</button>
        </div>
        <div class="hint mt-2">
            При первом запуске чек-лист создаётся автоматически. Повторная проверка
            обновит авто-статусы пунктов, которые можно определить по HTML.
        </div>
    </form>

    <!-- Блок "Точка остановки" НАВЕРХУ -->
    <div class="stop-point-box">
        <h5>🛑 Точка остановки</h5>
        <div class="sp-stage">Этап: <strong><?= htmlspecialchars($this->auditData['stop_point']) ?></strong></div>
        <div class="sp-item"><?= htmlspecialchars($this->auditData['stop_item']) ?></div>
    </div>

    <!-- Кнопка пересчёта + прогресс -->
    <div class="card-dark p-3 mb-3">
        <div class="d-flex flex-wrap justify-content-between align-items-center gap-3">
            <div class="d-flex gap-2">
                <form method="POST">
                    <input type="hidden" name="action" value="recalc">
                    <button type="submit" class="btn btn-accent btn-sm">🔄 Пересчитать прогресс</button>
                </form>
                <button class="btn btn-outline-light-audit btn-sm" data-bs-toggle="modal" data-bs-target="#addItemModal">
                    ➕ Добавить пункт
                </button>
            </div>
            <div class="flex-grow-1" style="min-width: 260px;">
                <div class="d-flex justify-content-between hint mb-1">
                    <span>Общая готовность</span>
                    <span>Готово <?= $this->auditData['ready_items'] ?> из <?= $this->auditData['total_items'] ?></span>
                </div>
                <div class="progress progress-custom">
                    <?php
                    $p = (int)$this->auditData['progress'];
                    $barClass = $p >= 90 ? 'bg-ready' : ($p >= 50 ? 'bg-mid' : 'bg-low');
                    ?>
                    <div class="progress-bar <?= $barClass ?>" role="progressbar"
                         style="width: <?= $p ?>%;" aria-valuenow="<?= $p ?>"
                         aria-valuemin="0" aria-valuemax="100"><?= $p ?>%</div>
                </div>
            </div>
        </div>
    </div>

    <!-- Шкала этапов -->
    <?php
    $stages = ['1. Контент и дизайн', '2. Техническая часть и SEO', '3. Функциональность и аналитика', '4. Хостинг и деплой', 'Пост-релиз (24ч)'];
    $stageState = [];
    foreach ($stages as $s) {
        $itemsIn = array_filter($this->auditData['items'], fn($it) => $it['stage'] === $s);
        $hasReady = false; $hasFail = false; $allReady = count($itemsIn) > 0;
        foreach ($itemsIn as $it) {
            if ($it['status'] === 'ready') $hasReady = true; else $allReady = false;
            if ($it['status'] !== 'ready') $hasFail = true;
        }
        if ($allReady && count($itemsIn) > 0) $stageState[$s] = 'done';
        elseif ($hasFail) $stageState[$s] = 'fail';
        elseif ($hasReady) $stageState[$s] = 'active';
        else $stageState[$s] = '';
    }
    ?>
    <div class="timeline-horizontal">
        <?php foreach ($stages as $i => $s): ?>
            <div class="tl-step <?= $stageState[$s] ?>">
                <div class="tl-dot"><?= $i + 1 ?></div>
                <div class="tl-label"><?= htmlspecialchars($s) ?></div>
            </div>
        <?php endforeach; ?>
    </div>

    <!-- Таблица чек-листа -->
    <div class="card-dark p-0 overflow-hidden">
        <div class="table-responsive">
            <table class="table table-dark-audit align-middle mb-0">
                <thead>
                    <tr>
                        <th style="width:5%;">№</th>
                        <th style="width:50%;">Пункт проверки</th>
                        <th style="width:20%;">Статус</th>
                        <th style="width:25%;">Действие</th>
                    </tr>
                </thead>
                <tbody>
                <?php if (empty($this->auditData['items'])): ?>
                    <tr><td colspan="4" class="text-center hint py-4">
                        Чек-лист пуст. Нажмите «Проверить» или «Добавить пункт».
                    </td></tr>
                <?php endif; ?>

                <?php $currentStage = null; foreach ($this->auditData['items'] as $item): ?>
                    <?php if ($item['stage'] !== $currentStage): $currentStage = $item['stage']; ?>
                        <tr class="stage-row">
                            <td colspan="4"><span class="stage-badge"><?= htmlspecialchars($currentStage) ?></span></td>
                        </tr>
                    <?php endif; ?>
                    <tr>
                        <td class="text-center"><?= htmlspecialchars($item['id']) ?></td>
                        <td>
                            <div class="item-name"><?= htmlspecialchars($item['name']) ?></div>
                            <?php if (!empty($item['note'])): ?>
                                <div class="note-muted"><?= htmlspecialchars($item['note']) ?></div>
                            <?php endif; ?>
                        </td>
                        <td class="text-center">
                            <span class="status-badge <?= $this->statusClass($item['status']) ?>">
                                <?= $this->statusLabel($item['status']) ?>
                            </span>
                        </td>
                        <td>
                            <div class="d-flex gap-2 flex-wrap">
                                <form method="POST" class="d-flex gap-1">
                                    <input type="hidden" name="action" value="update_status">
                                    <input type="hidden" name="item_id" value="<?= htmlspecialchars($item['id']) ?>">
                                    <select name="status" class="form-select form-select-sm action-select"
                                            onchange="this.form.submit()">
                                        <option value="ready" <?= $item['status']==='ready'?'selected':'' ?>>✅ Готово</option>
                                        <option value="warn"  <?= $item['status']==='warn'?'selected':'' ?>>⚠️ Пропущено</option>
                                        <option value="fail"  <?= $item['status']==='fail'?'selected':'' ?>>❌ Не готово</option>
                                    </select>
                                </form>
                                <form method="POST" onsubmit="return confirm('Удалить пункт?');">
                                    <input type="hidden" name="action" value="delete_item">
                                    <input type="hidden" name="item_id" value="<?= htmlspecialchars($item['id']) ?>">
                                    <button type="submit" class="btn btn-sm btn-danger-audit" title="Удалить">✕</button>
                                </form>
                            </div>
                        </td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    </div>

    <div class="hint mt-3">
        Пример модального окна с пояснением для одного пункта открывается по кнопке ниже —
        так можно показать пользователю, как заполнять пункт вручную.
    </div>
    <button class="btn btn-outline-light-audit btn-sm mt-2" data-bs-toggle="modal" data-bs-target="#exampleItemModal">
        Показать пример модального окна для пункта
    </button>
</div>

<!-- Модальное окно: добавление нового пункта -->
<div class="modal fade" id="addItemModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-lg modal-dialog-centered">
        <div class="modal-content">
            <form method="POST">
                <input type="hidden" name="action" value="add_item">
                <div class="modal-header">
                    <h5 class="modal-title">➕ Новый пункт проверки</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
                </div>
                <div class="modal-body">
                    <div class="mb-3">
                        <label class="form-label">Название пункта</label>
                        <input type="text" name="name" class="form-control" required
                               placeholder="Например: Проверка микроразметки Schema.org">
                    </div>
                    <div class="mb-3">
                        <label class="form-label">Этап</label>
                        <select name="stage" class="form-select">
                            <?php foreach ($stages as $s): ?>
                                <option value="<?= htmlspecialchars($s) ?>"><?= htmlspecialchars($s) ?></option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="mb-0">
                        <label class="form-label">Пояснение / заметка</label>
                        <textarea name="note" class="form-control" rows="3"
                                  placeholder="Что именно нужно проверить и как зафиксировать результат"></textarea>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-outline-light-audit" data-bs-dismiss="modal">Отмена</button>
                    <button type="submit" class="btn btn-accent">Добавить</button>
                </div>
            </form>
        </div>
    </div>
</div>

<!-- Модальное окно: ПРИМЕР с пояснением для одного пункта -->
<div class="modal fade" id="exampleItemModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-lg modal-dialog-centered">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">📌 Пример пункта: «Метатеги (title, description)»</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
            </div>
            <div class="modal-body">
                <p><strong>Этап:</strong> 2. Техническая часть и SEO</p>
                <p><strong>Что проверять:</strong> наличие тегов <code>&lt;title&gt;</code> и
                    <code>&lt;meta name="description"&gt;</code> в <code>&lt;head&gt;</code>,
                    их уникальность и длину (title ≈ 50–60 символов, description ≈ 150–160).</p>
                <p><strong>Как фиксировать статус:</strong></p>
                <ul>
                    <li><span class="status-badge st-ready">✅ Готово</span> — теги корректны.</li>
                    <li><span class="status-badge st-warn">⚠️ Пропущено</span> — проверить невозможно в текущих условиях.</li>
                    <li><span class="status-badge st-fail">❌ Не готово</span> — тегов нет или они некорректны.</li>
                </ul>
                <p class="hint mb-0">В строке таблицы статус меняется выпадающим списком — прогресс и
                    точка остановки пересчитываются сразу после сохранения.</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-accent" data-bs-dismiss="modal">Понятно</button>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
        <?php
    }
}

// ---------------------------------------------------------------------------
// Точка входа
// ---------------------------------------------------------------------------
$initialUrl = trim($_POST['url'] ?? '');
$audit = new WebPageAudit($initialUrl);


$audit->render();
?>