<?php
ob_start();
define('SITE_VERSION', '4.9.293');
date_default_timezone_set('Europe/Moscow');

define('P_V', substr(md5(filemtime(__FILE__)), 0, 8));


const MAINT_FLAG = __DIR__ . '/../storage/maintenance.lock';
const DEBUG_TOKEN_FILE = __DIR__ . '/../storage/debug_token.txt';

// Функция для генерации безопасного debug токена
function getOrCreateDebugToken()
{
    if (!file_exists(DEBUG_TOKEN_FILE)) {
        $token = bin2hex(random_bytes(32));
        file_put_contents(DEBUG_TOKEN_FILE, $token, LOCK_EX);
        return $token;
    }
    return trim(file_get_contents(DEBUG_TOKEN_FILE));
}

const DEBUG_COOKIE = 'rmrp_debug';

// Обработка debug режима с безопасным токеном
if (isset($_GET['debug'])) {
    $debugToken = getOrCreateDebugToken();
    if (hash_equals($debugToken, (string) $_GET['debug'])) {
        // Определяем схему (http/https) более надёжным способом
        $isSecure = (
            (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
            (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') ||
            (!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') ||
            (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443)
        );

        setcookie(DEBUG_COOKIE, '1', [
            'expires' => time() + 3600,
            'path' => '/',
            'secure' => $isSecure,
            'httponly' => true,
            'samesite' => 'Lax',
        ]);

        // Редиректим на ту же страницу без параметра debug
        $protocol = $isSecure ? 'https' : 'http';
        $host = $_SERVER['HTTP_HOST'];
        $uri = strtok($_SERVER['REQUEST_URI'], '?');

        header('Location: ' . $protocol . '://' . $host . $uri, true, 302);
        exit;
    }
}

$isDebugViewer = isset($_COOKIE[DEBUG_COOKIE]) && $_COOKIE[DEBUG_COOKIE] === '1';

// Режим обслуживания
if (file_exists(MAINT_FLAG) && !$isDebugViewer) {
    http_response_code(503);
    header('Retry-After: 300');

    // Используем новую страницу обслуживания
    $maintenancePage = __DIR__ . '/../pages/maintenance.html';
    if (file_exists($maintenancePage)) {
        readfile($maintenancePage);
    } else {
        echo "<h1>Сервис недоступен (503)</h1><p>Ведутся технические работы.</p>";
    }
    exit;
}

ini_set('display_errors', '0');
error_reporting(E_ALL);

// Обработчик ошибок
set_error_handler(function ($severity, $message, $file, $line) {
    if (!(error_reporting() & $severity))
        return false;
    throw new ErrorException($message, 0, $severity, $file, $line);
});

// Обработчик исключений с безопасным выводом
set_exception_handler(function ($e) use ($isDebugViewer) {
    http_response_code(500);
    if ($isDebugViewer) {
        echo "<pre style='white-space:pre-wrap;background:#0b1220;color:#eaf2ff;padding:16px;border-radius:10px;'>" .
            "⚠️ Exception: " . htmlspecialchars($e->getMessage(), ENT_QUOTES | ENT_HTML5, 'UTF-8') . "\n\n" .
            htmlspecialchars($e->getTraceAsString(), ENT_QUOTES | ENT_HTML5, 'UTF-8') .
            "</pre>";
    } else {
        // Показываем красивую страницу ошибки 500
        $errorPage = __DIR__ . '/../pages/errors.php';
        if (file_exists($errorPage)) {
            $_GET['code'] = '500';
            include $errorPage;
        } else {
            echo "<h1>Внутренняя ошибка (500)</h1><p>Мы уже работаем над исправлением.</p>";
        }
    }
    exit;
});

// Обработчик фатальных ошибок
register_shutdown_function(function () use ($isDebugViewer) {
    $err = error_get_last();
    if ($err && in_array($err['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE], true)) {
        http_response_code(500);
        if ($isDebugViewer) {
            echo "<pre style='white-space:pre-wrap;background:#0b1220;color:#eaf2ff;padding:16px;border-radius:10px;'>" .
                "💥 Fatal: " . htmlspecialchars($err['message'], ENT_QUOTES | ENT_HTML5, 'UTF-8') . "\n" .
                "File: " . htmlspecialchars($err['file'], ENT_QUOTES | ENT_HTML5, 'UTF-8') . ":" . $err['line'] .
                "</pre>";
        } else {
            // Показываем красивую страницу ошибки 500
            $errorPage = __DIR__ . '/../pages/errors.php';
            if (file_exists($errorPage)) {
                $_GET['code'] = '500';
                include $errorPage;
            } else {
                echo "<h1>Внутренняя ошибка (500)</h1><p>Мы уже работаем над исправлением.</p>";
            }
        }
    }
});

$pages = [
    'login' => '/../pages/login.php',
    'reg' => '/../pages/reg.php',
    'logout' => '/../pages/login.php',
    'no_access' => '/../pages/no_access.php',
    'errors' => '/../pages/errors.php',
    'maintenance_control' => '/../pages/maintenance_control.php',
    'schedule' => '/../pages/schedule.php',
    'recordings' => '/../pages/recordings.php',
    'people' => '/../pages/people.php',
    'profile' => '/../pages/profile.php',
    'work' => '/../pages/work.php',
    'stats' => '/../pages/stats.php',
    'promocodes' => '/../pages/promocodes.php',
    'duties' => '/../pages/duties.php',
    'admin' => '/../pages/admin.php',
    'create_admin' => '/../pages/create_admin.php',
    'notes' => '/../pages/notes.php',
    'metadata' => '/../pages/metadata.php',
    'faq' => '/../pages/faq.php',
    'terms' => '/../pages/terms.php',
    'privacy' => '/../pages/privacy.php',
    'password' => '/../pages/login.php',
    'reg_form'=> '/../pages/reg_form.php',
    'setup_2fa' => '/../pages/setup_2fa.php',
    'manage_2fa' => '/../pages/manage_2fa.php',
    'api' => '/../pages/api_help.html',
    'bot_schedule' => '/public/bot_schedule.php',
    'raffle_stat' => '/../pages/raffle_ng/raffle_stat.php'
];

require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/perms.php';
require_once __DIR__ . '/../includes/telegram.php';
require_once __DIR__ . '/../includes/util.php';
require_once __DIR__ . '/../includes/session_handler.php';

// Безопасный запуск сессии (хранение в БД, таблица sessions)
if (session_status() !== PHP_SESSION_ACTIVE) {
    ini_set('session.gc_maxlifetime', 345600);
    ini_set('session.cookie_lifetime', 345600);
    ini_set('session.cookie_httponly', 1);
    ini_set('session.cookie_secure', (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 1 : 0);
    ini_set('session.use_strict_mode', 1);
    ini_set('session.cookie_samesite', 'Lax');

    $handler = new DatabaseSessionHandler();
    session_set_save_handler($handler, true);

    @session_start();

    // Обновляем время активности при каждом запросе
    if (isset($_SESSION['LAST_ACTIVITY'])) {
        // Если прошло более 30 минут бездействия, продлеваем сессию
        if (time() - $_SESSION['LAST_ACTIVITY'] > 1800) {
            session_regenerate_id(false); // Регенерируем ID без удаления старых данных
        }
    }
    $_SESSION['LAST_ACTIVITY'] = time();
}

// Генерируем CSRF токен для сессии, если его ещё нет
if (!isset($_SESSION['csrf'])) {
    $_SESSION['csrf'] = bin2hex(random_bytes(32));
}

$page = $_GET['page'] ?? 'schedule';
$page = preg_replace('/[^a-zA-Z0-9_]/', '', $page);


$public_pages = ['login', 'no_access', 'errors', 'reg', 'create_admin', 'api_get_schedule', 'api_host_about', 'api'];
if (!in_array($page, $public_pages)) {
    if (!function_exists('require_login')) {
        // Базовая проверка авторизации, если функция не определена
        if (!isset($_SESSION['user_id'])) {
            header('Location: /login');
            exit;
        }
    } else {
        require_login();
        
        // Проверяем обязательность 2FA (кроме страниц настройки 2FA и выхода)
        if ($page !== 'setup_2fa' && $page !== 'logout' && $page !== 'manage_2fa') {
            if (function_exists('require_2fa')) {
                require_2fa();
            }
        }
    }
}

if ($page === 'api_get_schedule') {
    header('Content-Type: application/json; charset=utf-8');
    header('Access-Control-Allow-Origin: *');
    
    // Проверяем существование функции db()
    if (!function_exists('db')) {
        http_response_code(500);
        echo json_encode(['error' => 'Database connection not available'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    // Получаем параметры из GET-запроса
    $load_start = $_GET['load_start'] ?? null;
    $load_end = $_GET['load_end'] ?? null;
    $host_id = $_GET['host_id'] ?? null;
    $last = $_GET['last'] ?? null;

    // Валидация формата дат
    if ($load_start && !strtotime($load_start)) {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid load_start date format'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ($load_end && !strtotime($load_end)) {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid load_end date format'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    // Валидация host_id
    if ($host_id !== null) {
        $host_id = filter_var($host_id, FILTER_VALIDATE_INT);
        if ($host_id === false || $host_id <= 0) {
            http_response_code(400);
            echo json_encode(['error' => 'Invalid host_id'], JSON_UNESCAPED_UNICODE);
            exit;
        }
    }

    // Валидация last
    if ($last !== null) {
        $last = filter_var($last, FILTER_VALIDATE_INT);
        if ($last === false || $last <= 0) {
            http_response_code(400);
            echo json_encode(['error' => 'Invalid last parameter'], JSON_UNESCAPED_UNICODE);
            exit;
        }
    }

    try {
        // Проверяем существование колонки is_deleted
        $columnExists = false;
        try {
            $checkColumn = db()->prepare("SELECT is_deleted FROM shows LIMIT 1");
            $checkColumn->execute();
            $columnExists = true;
        } catch (Exception $e) {
            // Колонка не существует, продолжаем без неё
            $columnExists = false;
        }

        // Базовый SQL запрос с добавлением u.id и bio
        $sql = "SELECT s.id, s.title, s.planned_at, s.duration_min, u.id as host_id, u.full_name, u.nickname, u.bio
                FROM shows s JOIN users u ON u.id = s.host_id";
        
        $params = [];
        $conditions = [];

        // Фильтруем только активные эфиры (не удаленные), если колонка существует
        if ($columnExists) {
            $conditions[] = "(s.is_deleted = 0 OR s.is_deleted IS NULL)";
        }

        // Добавляем условия фильтрации по датам
        if ($load_start) {
            $conditions[] = "s.planned_at >= ?";
            $params[] = $load_start;
        }
        if ($load_end) {
            $conditions[] = "s.planned_at <= ?";
            $params[] = $load_end;
        }

        // Добавляем фильтрацию по ведущему
        if ($host_id !== null) {
            $conditions[] = "s.host_id = ?";
            $params[] = $host_id;
        }

        // Формируем WHERE clause если есть условия
        if (!empty($conditions)) {
            $sql .= " WHERE " . implode(' AND ', $conditions);
        }

        $sql .= " ORDER BY s.planned_at DESC";

        // Добавляем LIMIT если указан параметр last (как позиционный параметр)
        if ($last !== null) {
            $sql .= " LIMIT ?";
            $params[] = $last;
        }

        // Используем prepared statements для безопасности
        $st = db()->prepare($sql);

        // Привязываем параметры вручную с правильными типами
        $paramIndex = 1;
        foreach ($params as $param) {
            if (is_int($param)) {
                $st->bindValue($paramIndex++, $param, PDO::PARAM_INT);
            } else {
                $st->bindValue($paramIndex++, $param, PDO::PARAM_STR);
            }
        }

        $st->execute();
        $rows = $st->fetchAll(PDO::FETCH_ASSOC);

        // Формируем массив с данными эфиров
        $out = [];
        foreach ($rows as $row) {
            $host = trim((string) ($row['nickname'] ?? '')) !== '' ? $row['nickname'] : $row['full_name'];
            
            $out[] = [
                'id' => (int) $row['id'],
                'title' => (string) $row['title'],
                'start' => (string) $row['planned_at'],
                'duration_min' => (int) $row['duration_min'],
                'host' => (string) $host,
                'host_id' => (int) $row['host_id'],
                'host_full_name' => (string) $row['full_name'],
                'host_bio' => (string) ($row['bio'] ?? ''),
            ];
        }

        echo json_encode($out, JSON_UNESCAPED_UNICODE);
        exit;
    } catch (Exception $e) {
        error_log("API get_schedule error: " . $e->getMessage());
        http_response_code(500);
        echo json_encode(['error' => 'Database error', 'details' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
        exit;
    }
}

// API endpoint для информации об эфире
if ($page === 'api_show_info') {
    header('Content-Type: application/json; charset=utf-8');

    $id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
    if ($id === false || $id <= 0) {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid ID'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    // Проверяем существование функции db()
    if (!function_exists('db')) {
        http_response_code(500);
        echo json_encode(['error' => 'Database connection not available'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    try {
        // Попробуем запрос с is_deleted и show_deletion_log
        try {
            $st = db()->prepare("SELECT s.id, s.title, s.planned_at, s.duration_min, s.is_deleted, 
                                         u.full_name, u.nickname,
                                         sdl.deleted_by_name, sdl.deletion_reason, sdl.deleted_at
                                  FROM shows s 
                                  JOIN users u ON u.id = s.host_id
                                  LEFT JOIN show_deletion_log sdl ON s.id = sdl.show_id AND s.is_deleted = 1
                                  WHERE s.id = ?");
            $st->execute([$id]);
            $row = $st->fetch();
        } catch (Exception $e) {
            // Если ошибка (таблица или колонка не существует), используем упрощённый запрос
            $st = db()->prepare("SELECT s.id, s.title, s.planned_at, s.duration_min,
                                         u.full_name, u.nickname
                                  FROM shows s 
                                  JOIN users u ON u.id = s.host_id
                                  WHERE s.id = ?");
            $st->execute([$id]);
            $row = $st->fetch();
        }

        if (!$row) {
            http_response_code(404);
            echo json_encode(['error' => 'not found'], JSON_UNESCAPED_UNICODE);
            exit;
        }

        // Найдём последнюю запись
        $rr = db()->prepare("SELECT file_path FROM recordings WHERE show_id=? AND published=1 ORDER BY id DESC LIMIT 1");
        $rr->execute([$id]);
        $recUrl = $rr->fetchColumn() ?: null;

        $host = trim((string) ($row['nickname'] ?? '')) !== '' ? $row['nickname'] : $row['full_name'];
        $out = [
            'id' => (int) $row['id'],
            'title' => (string) $row['title'],
            'start' => (string) $row['planned_at'],
            'duration_min' => (int) $row['duration_min'],
            'host' => (string) $host,
            'recording_url' => $recUrl,
            'is_deleted' => (int) ($row['is_deleted'] ?? 0),
            'deleted_by_name' => $row['deleted_by_name'] ?? null,
            'deletion_reason' => $row['deletion_reason'] ?? null,
            'deleted_at' => $row['deleted_at'] ?? null,
        ];

        echo json_encode($out, JSON_UNESCAPED_UNICODE);
        exit;
    } catch (Exception $e) {
        error_log("API show_info error: " . $e->getMessage());
        http_response_code(500);
        echo json_encode(['error' => 'Database error', 'details' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
        exit;
    }
}

// API endpoint для информации о ведущем/ведущих
if ($page === 'api_host_about') {
    header('Content-Type: application/json; charset=utf-8');

    $host_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
    
    // Если ID не указан или равен null, возвращаем список всех ведущих
    $get_all_hosts = !isset($_GET['id']) || $host_id === null || $host_id === false;
    
    // Если ID указан, но невалиден
    if (isset($_GET['id']) && ($host_id === false || $host_id <= 0)) {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid ID'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    if (!function_exists('db')) {
        http_response_code(500);
        echo json_encode(['error' => 'Database connection not available'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    try {
        // Проверяем существование колонки is_deleted
        $columnExists = false;
        try {
            $checkColumn = db()->prepare("SELECT is_deleted FROM shows LIMIT 1");
            $checkColumn->execute();
            $columnExists = true;
        } catch (Exception $e) {
            $columnExists = false;
        }

        if ($get_all_hosts) {
            // Возвращаем список всех ведущих
            $st = db()->prepare("
                SELECT DISTINCT u.id, u.full_name, u.nickname, u.bio, u.avatar, u.created_at
                FROM users u
                JOIN user_roles ur ON ur.user_id = u.id
                JOIN roles r ON r.id = ur.role_id
                WHERE u.is_active = 1 AND r.key_name LIKE 'host%'
                ORDER BY u.full_name ASC
            ");
            $st->execute();
            $hosts = $st->fetchAll(PDO::FETCH_ASSOC);

            $out = [];
            foreach ($hosts as $user) {
                // Получаем роли для каждого ведущего
                $rolesStmt = db()->prepare("
                    SELECT r.title, r.key_name
                    FROM user_roles ur
                    JOIN roles r ON ur.role_id = r.id
                    WHERE ur.user_id = ?
                    ORDER BY r.display_order ASC, r.title ASC
                ");
                $rolesStmt->execute([$user['id']]);
                $roles = $rolesStmt->fetchAll(PDO::FETCH_ASSOC);

                // Получаем статистику
                if ($columnExists) {
                    $statsStmt = db()->prepare("
                        SELECT 
                            COUNT(DISTINCT s.id) as total_shows,
                            COALESCE(SUM(s.duration_min), 0) as total_minutes,
                            (SELECT COUNT(*) FROM recordings r 
                             JOIN shows sh ON r.show_id = sh.id 
                             WHERE (sh.host_id = ? OR sh.cohost_id = ?) AND (sh.is_deleted = 0 OR sh.is_deleted IS NULL)) as total_recordings,
                            SUM(CASE WHEN s.host_id = ? THEN 1 ELSE 0 END) as host_count,
                            SUM(CASE WHEN s.cohost_id = ? THEN 1 ELSE 0 END) as cohost_count
                        FROM shows s
                        WHERE (s.status = 'planned' OR s.status = 'done')
                        AND (s.is_deleted = 0 OR s.is_deleted IS NULL)
                        AND (s.host_id = ? OR s.cohost_id = ?)
                    ");
                } else {
                    $statsStmt = db()->prepare("
                        SELECT 
                            COUNT(DISTINCT s.id) as total_shows,
                            COALESCE(SUM(s.duration_min), 0) as total_minutes,
                            (SELECT COUNT(*) FROM recordings r 
                             JOIN shows sh ON r.show_id = sh.id 
                             WHERE (sh.host_id = ? OR sh.cohost_id = ?)) as total_recordings,
                            SUM(CASE WHEN s.host_id = ? THEN 1 ELSE 0 END) as host_count,
                            SUM(CASE WHEN s.cohost_id = ? THEN 1 ELSE 0 END) as cohost_count
                        FROM shows s
                        WHERE (s.status = 'planned' OR s.status = 'done')
                        AND (s.host_id = ? OR s.cohost_id = ?)
                    ");
                }
                $statsStmt->execute([$user['id'], $user['id'], $user['id'], $user['id'], $user['id'], $user['id']]);
                $stats = $statsStmt->fetch(PDO::FETCH_ASSOC);

                $displayName = trim((string) ($user['nickname'] ?? '')) !== '' ? $user['nickname'] : $user['full_name'];
                $avatarUrl = null;
                if (!empty($user['avatar']) && file_exists(__DIR__ . '/../storage/avatars/' . basename($user['avatar']))) {
                    $avatarUrl = '/storage/avatars/' . basename($user['avatar']);
                }

                $out[] = [
                    'id' => (int) $user['id'],
                    'full_name' => (string) $user['full_name'],
                    'nickname' => (string) ($user['nickname'] ?? ''),
                    'display_name' => $displayName,
                    'bio' => (string) ($user['bio'] ?? ''),
                    'avatar' => $avatarUrl,
                    'level' => (string) ($user['level'] ?? ''),
                    'roles' => array_map(function($role) {
                        return [
                            'title' => (string) $role['title'],
                            'key' => (string) $role['key_name']
                        ];
                    }, $roles),
                    'stats' => [
                        'total_shows' => (int) ($stats['total_shows'] ?? 0),
                        'total_minutes' => (int) ($stats['total_minutes'] ?? 0),
                        'total_recordings' => (int) ($stats['total_recordings'] ?? 0),
                        'as_host' => (int) ($stats['host_count'] ?? 0),
                        'as_cohost' => (int) ($stats['cohost_count'] ?? 0),
                    ],
                ];
            }

            echo json_encode($out, JSON_UNESCAPED_UNICODE);
            exit;
        }
        
        // Получаем информацию о конкретном ведущем
        $st = db()->prepare("
            SELECT u.id, u.full_name, u.nickname, u.bio, u.avatar, u.level, u.created_at,
                   u.telegram, u.discord, u.server, u.player_id
            FROM users u
            WHERE u.id = ? AND u.is_active = 1
        ");
        $st->execute([$host_id]);
        $user = $st->fetch();

        if (!$user) {
            http_response_code(404);
            echo json_encode(['error' => 'Host not found'], JSON_UNESCAPED_UNICODE);
            exit;
        }

        // Проверяем, является ли пользователь ведущим
        $roleCheck = db()->prepare("
            SELECT COUNT(*) as is_host
            FROM user_roles ur
            JOIN roles r ON ur.role_id = r.id
            WHERE ur.user_id = ? AND r.key_name LIKE 'host%'
        ");
        $roleCheck->execute([$host_id]);
        $isHost = (int) $roleCheck->fetch()['is_host'] > 0;

        if (!$isHost) {
            http_response_code(404);
            echo json_encode(['error' => 'User is not a host'], JSON_UNESCAPED_UNICODE);
            exit;
        }

        // Получаем роли ведущего
        $rolesStmt = db()->prepare("
            SELECT r.title, r.key_name
            FROM user_roles ur
            JOIN roles r ON ur.role_id = r.id
            WHERE ur.user_id = ?
            ORDER BY r.display_order ASC, r.title ASC
        ");
        $rolesStmt->execute([$host_id]);
        $roles = $rolesStmt->fetchAll(PDO::FETCH_ASSOC);

        // Получаем статистику ведущего (только активные эфиры)
        if ($columnExists) {
            $statsStmt = db()->prepare("
                SELECT 
                    COUNT(DISTINCT s.id) as total_shows,
                    COALESCE(SUM(s.duration_min), 0) as total_minutes,
                    (SELECT COUNT(*) FROM recordings r 
                     JOIN shows sh ON r.show_id = sh.id 
                     WHERE (sh.host_id = ? OR sh.cohost_id = ?) AND (sh.is_deleted = 0 OR sh.is_deleted IS NULL)) as total_recordings,
                    SUM(CASE WHEN s.host_id = ? THEN 1 ELSE 0 END) as host_count,
                    SUM(CASE WHEN s.cohost_id = ? THEN 1 ELSE 0 END) as cohost_count
                FROM shows s
                WHERE (s.status = 'planned' OR s.status = 'done')
                AND (s.is_deleted = 0 OR s.is_deleted IS NULL)
                AND (s.host_id = ? OR s.cohost_id = ?)
            ");
        } else {
            $statsStmt = db()->prepare("
                SELECT 
                    COUNT(DISTINCT s.id) as total_shows,
                    COALESCE(SUM(s.duration_min), 0) as total_minutes,
                    (SELECT COUNT(*) FROM recordings r 
                     JOIN shows sh ON r.show_id = sh.id 
                     WHERE (sh.host_id = ? OR sh.cohost_id = ?)) as total_recordings,
                    SUM(CASE WHEN s.host_id = ? THEN 1 ELSE 0 END) as host_count,
                    SUM(CASE WHEN s.cohost_id = ? THEN 1 ELSE 0 END) as cohost_count
                FROM shows s
                WHERE (s.status = 'planned' OR s.status = 'done')
                AND (s.host_id = ? OR s.cohost_id = ?)
            ");
        }
        $statsStmt->execute([$host_id, $host_id, $host_id, $host_id, $host_id, $host_id]);
        $stats = $statsStmt->fetch(PDO::FETCH_ASSOC);

        // Формируем ответ
        $displayName = trim((string) ($user['nickname'] ?? '')) !== '' ? $user['nickname'] : $user['full_name'];
        $avatarUrl = null;
        if (!empty($user['avatar']) && file_exists(__DIR__ . '/../storage/avatars/' . basename($user['avatar']))) {
            $avatarUrl = '/storage/avatars/' . basename($user['avatar']);
        }

        $out = [
            'id' => (int) $user['id'],
            'full_name' => (string) $user['full_name'],
            'nickname' => (string) ($user['nickname'] ?? ''),
            'display_name' => $displayName,
            'bio' => (string) ($user['bio'] ?? ''),
            'avatar' => $avatarUrl,
            'level' => (string) ($user['level'] ?? ''),
            'created_at' => (string) $user['created_at'],
            'roles' => array_map(function($role) {
                return [
                    'title' => (string) $role['title'],
                    'key' => (string) $role['key_name']
                ];
            }, $roles),
            'stats' => [
                'total_shows' => (int) ($stats['total_shows'] ?? 0),
                'total_minutes' => (int) ($stats['total_minutes'] ?? 0),
                'total_recordings' => (int) ($stats['total_recordings'] ?? 0),
                'as_host' => (int) ($stats['host_count'] ?? 0),
                'as_cohost' => (int) ($stats['cohost_count'] ?? 0),
            ],
            'contacts' => [
                'telegram' => (string) ($user['telegram'] ?? ''),
                'discord' => (string) ($user['discord'] ?? ''),
            ],
            'game_info' => [
                'server' => (string) ($user['server'] ?? ''),
                'player_id' => (string) ($user['player_id'] ?? ''),
            ]
        ];

        echo json_encode($out, JSON_UNESCAPED_UNICODE);
        exit;
    } catch (Exception $e) {
        error_log("API host_about error: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine());
        http_response_code(500);
        echo json_encode(['error' => 'Database error', 'details' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
        exit;
    }
}

// API endpoint для проверки пересечений
if ($page === 'api_check_overlap') {
    header('Content-Type: application/json; charset=utf-8');

    $id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) ?: 0;
    $start = $_GET['start'] ?? '';
    $start = htmlspecialchars(trim($start), ENT_QUOTES, 'UTF-8');
    $duration = filter_input(INPUT_GET, 'duration', FILTER_VALIDATE_INT) ?: 60;

    // Валидация времени
    $start = trim($start);
    if ($start !== '') {
        $start = str_replace('T', ' ', $start);
        if (preg_match('/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}$/', $start)) {
            $start .= ':00';
        }
        $dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $start);
        if (!$dateTime || $dateTime->format('Y-m-d H:i:s') !== $start) {
            http_response_code(400);
            echo json_encode(['error' => 'Invalid date format'], JSON_UNESCAPED_UNICODE);
            exit;
        }
    }

    if (!function_exists('db')) {
        http_response_code(500);
        echo json_encode(['error' => 'Database connection not available'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    try {
        $sql = "
            SELECT COUNT(*) AS c
            FROM shows
            WHERE id <> ?
              AND is_deleted = 0
              AND NOT (
                    DATE_ADD(?, INTERVAL ? MINUTE) <= planned_at
                OR  ? >= DATE_ADD(planned_at, INTERVAL duration_min MINUTE)
              )
        ";
        $stmt = db()->prepare($sql);
        $stmt->execute([$id, $start, $duration, $start]);
        $cnt = (int) $stmt->fetchColumn();

        echo json_encode(['overlap' => $cnt > 0, 'count' => $cnt], JSON_UNESCAPED_UNICODE);
        exit;
    } catch (Exception $e) {
        http_response_code(500);
        echo json_encode(['error' => 'Database error'], JSON_UNESCAPED_UNICODE);
        exit;
    }
}

function feature_enabled($key)
{
    if (!function_exists('db')) {
        return true;
    }

    try {
        $row = db()->query('SELECT features FROM settings WHERE id=1')->fetch();
        if (!$row || !$row['features'])
            return true;

        $features = json_decode($row['features'], true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return true;
        }

        return ($features[$key] ?? true) === true;
    } catch (Exception $e) {
        return true;
    }
}

$active = $page;

function render_header($active)
{
    $u = function_exists('current_user') ? current_user() : null;

    $items = [
        'schedule' => ['Сетка эфиров', 'schedule.read'],
        'recordings' => ['Записи', 'recordings.read'],
        'people' => ['Состав', 'people.read'],
        'work' => ['Проделанная работа', 'work.read_own'],
        'stats' => ['Статистика', 'admin.access'],
        'promocodes' => ['Промокоды', 'promocodes.read'],
        'duties' => ['Обязанности', 'duties.read'],
        'admin' => ['Админка', 'admin.access'],
        'reg_form' => ['Заявки','admin.access'],
        'notes' => ['Заметки', 'notes.read_write'],
        'metadata' => ['Меты', 'meta.read'],
        'faq' => ['FAQ', 'training.read'],
        'raffle_stat' => ['Розыгрыш стат.', 'admin.access']
    ];

    echo '<!doctype html><html lang="ru" data-theme="light"><head>';
    echo '<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">';
    echo '<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon.jpeg">';
    echo '<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon.jpeg">';
    echo '<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon.jpeg">';
    echo '<link rel="icon" type="image/png" href="/assets/favicon.jpeg">';
    echo '<link rel="stylesheet" href="/assets/styles.css?v=<?php echo P_V; ?>">';
    echo '<link rel="stylesheet" href="/assets/user-status.css?v=<?php echo P_V; ?>">';
    echo '<link rel="stylesheet" href="/assets/profile.css?v=<?php echo P_V; ?>">';
    echo '<link rel="stylesheet" href="/assets/admin.css?v=<?php echo P_V; ?>">';

    echo '<script>';
    echo 'const savedTheme=localStorage.getItem("theme")||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");';
    echo 'document.documentElement.setAttribute("data-theme",savedTheme);';
    echo 'function __updateThemeButton(){const btn=document.getElementById("theme-toggle");const icon=btn&&btn.querySelector(".theme-icon");const current=document.documentElement.getAttribute("data-theme");if(btn){btn.setAttribute("aria-pressed",current==="dark"?"true":"false");if(icon){icon.textContent=current==="dark"?"☀️":"🌙";}}}';
    echo 'document.addEventListener("DOMContentLoaded",function(){__updateThemeButton();const btn=document.getElementById("theme-toggle");if(btn){btn.addEventListener("click",function(){const cur=document.documentElement.getAttribute("data-theme");const next=cur==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",next);localStorage.setItem("theme",next);__updateThemeButton();});}});';
    echo '</script>';

    echo '<script defer src="/assets/app.js?v=<?php echo P_V; ?>"></script>';
    echo '<script defer src="/assets/admin.js?v=<?php echo P_V; ?>"></script>';
    echo '<script defer src="/assets/schedule.js?v=<?php echo P_V; ?>"></script>';
    echo '<script defer src="/assets/user-status.js?v=<?php echo P_V; ?>"></script>';

    $greetings = ['Хорошего настроения', 'Отличного дня', 'Приятного дня', 'Доброго дня', 'Успешного дня', 'Удачного дня', 'Прекрасного настроения', 'Солнечного дня', 'Хороших новостей', 'Чудесного утра', 'Радостного вечера', 'Пусть день радует', 'Тепла и уюта', 'Гармонии в душе', 'Прекрасного времени', 'Пусть всё получится', 'Легкости и вдохновения', 'Добра и радости', 'Позитивного настроя', 'Побольше улыбок', 'Счастливого дня', 'Мирного утра', 'Теплых мыслей', 'Радости каждый день', 'Отличного настроения', 'Хорошего самочувствия', 'Позитива и света', 'Улыбнись сегодня'];
    $userName = $u ? ($u['nickname'] ?: $u['full_name']) : 'Гость';
    echo '<title>ML Staff Portal. ' . htmlspecialchars($greetings[array_rand($greetings)], ENT_QUOTES) . ', ' . htmlspecialchars($userName, ENT_QUOTES). '!</title></head><body class="logged-in" data-page="' . htmlspecialchars($active, ENT_QUOTES) . '">';

    echo '<div class="layout">';

    echo '<aside id="sidebar" class="sidebar">';
    echo '<div class="brand">';
    echo '<span class="dot"></span>Moscow Live';

    echo '<button id="theme-toggle" class="theme-toggle" title="Переключить тему" aria-pressed="false">';
    echo '<span class="theme-icon">🌙</span>';
    echo '</button>';

    echo '</div>';

    echo '<nav class="sidenav" id="mainNav">';

    foreach ($items as $k => $v) {
        $hasPermission = !function_exists('has_perm') || has_perm($v[1]);
        if (!$hasPermission)
            continue;

        $cls = $k === $active ? 'active' : '';
        $pageParam = htmlspecialchars($k, ENT_QUOTES);
        
        // Специальная обработка для stats - перенаправляем сразу на /stats/overview
        $href = ($k === 'stats') ? '/stats/overview' : '/' . $pageParam;
        
        echo '<a class="' . $cls . '" href="' . $href . '"><span class="icon">•</span><span class="label">' . htmlspecialchars($v[0]) . '</span></a>';
    }

    if ($u) {
        echo '<hr class="profile-divider">';
        echo '<div class="profile-section">';
        $profileCls = $active === 'profile' ? 'active' : '';
        echo '<a class="profile-link ' . $profileCls . '" href="/profile">';
        echo '<span class="profile-icon">👤</span>';
        echo '<span class="profile-label">Профиль</span>';
        echo '</a>';
        echo '</div>';
    }

    echo '</nav>';
    echo '</aside>';

    echo '<button id="sidebarToggle" class="sidebar-fab" aria-label="Меню" aria-expanded="false">'.'<span class="bar"></span>'.'<span class="bar"></span>'.'<span class="bar"></span>'.'</button>';

    echo '<main class="main">';
    echo '<div class="container">';
}
function render_footer()
{
    $version = defined('SITE_VERSION') ? SITE_VERSION : '1.0.0';
    $buildNumber = filemtime(__FILE__);
    $buildDate = date('Y.m.d', $buildNumber);
    
    echo '</div>'; // Закрываем container
    
    echo '<footer class="site-footer">';
    echo '<div class="footer-wrapper">';
    
    // Основная сетка
    echo '<div class="footer-grid">';
    
    // Колонка 1 - Информация
    echo '<div class="footer-col">';
    echo '<div class="footer-heading footer-brand">Москва-лайв</div>';
    echo '<div class="footer-copyright">© ' . date('Y') . ' Внутренний служебный портал.<br>Все права защищены.</div>';
    echo '<div class="footer-text">';
    echo 'Используя данный портал, вы соглашаетесь с ';
    echo '<a href="https://forum.rmrp.ru/#pravila-proekta.306" target="_blank" rel="noopener">Правилами проекта RMRP</a> и ';
    echo '<a href="/terms">Внутренним уставом Москва-LIVE</a>. ';
    echo 'Несанкционированный доступ запрещен. ';
    echo 'Дисциплинарные меры применяются согласно Правилам и Уставу. ';
    echo 'Незнание правил не освобождает от ответственности.';
    echo '</div>';
    echo '</div>';
    
    // Колонка 2 - Ресурсы радио
    echo '<div class="footer-col">';
    echo '<div class="footer-heading">Ресурсы радио</div>';
    echo '<ul class="footer-links">';
    echo '<li><a href="https://cast.rmrp.ru" target="_blank" rel="noopener">Радио онлайн</a></li>';
    echo '<li><a href="https://t.me/ml_rmrp_bot" target="_blank" rel="noopener">Радио в ТГ</a></li>';
    echo '<li><a href="https://join.work-ml.ru" target="_blank" rel="noopener">Оставить заявку на работу</a></li>';
    echo '<li><a href="https://discord.gg/NtDybbyGMA" target="_blank" rel="noopener">Discord сервер</a></li>';
    echo '<li><a href="https://t.me/MLRMRP" target="_blank" rel="noopener">ТГК</a></li>';
    echo '<li><a href="https://t.me/ML_RMRP_CHAT" target="_blank" rel="noopener">Заказ песен/приветов, расписание эфиров</a></li>';
    echo '<li><a href="https://vk.com/mlrmrp" target="_blank" rel="noopener">ВКонтакте</a></li>';
    echo '<li><a href="/api">API</a></li>';
    echo '</ul>';
    echo '</div>';

    // Колонка 3 - Руководство радио
    echo '<div class="footer-col">';
    echo '<div class="footer-heading">Руководство радио</div>';
    echo '<div class="footer-team">';
    echo '<div class="team-item">';
    echo '<div class="team-name">Елизовета Белова</div>';
    echo '<div class="team-role">Главный администратор медиа</div>';
    echo '</div>';
    echo '<div class="team-item">';
    echo '<div class="team-name">Артём Борнитов</div>';
    echo '<div class="team-role">Главный куратор</div>';
    echo '</div>';
    echo '<div class="team-item">';
    echo '<div class="team-name">Степан Зайцев (megafon)</div>';
    echo '<div class="team-role">Заместитель ГК</div>';
    echo '</div>';
    echo '</div>';
    echo '</div>';
    echo '</div>';

    // Колонка 4 - Остались вопросы?
    echo '<div class="footer-col">';
    echo '<div class="footer-heading">Остались вопросы?</div>';
    echo '<div class="footer-team">';
    echo '<div class="team-item">';
    echo '<div class="team-name"><a href="https://t.me/V00KO" target="_blank" rel="noopener">Степан Зайцев (megafon)</a></div>';
    echo '<div class="team-role">Разработка сайта, техническая поддержка радио. Обращаться по любым вопросам</div>';
    echo '</div>';
    echo '<div class="team-item">';
    echo '<div class="team-name"><a href="https://t.me/ti8idi" target="_blank" rel="noopener">Артём Борнитов</a></div>';
    echo '<div class="team-role">Главный куратор радио. Обращаться по любым вопросам, кроме тех. части.</div>';
    echo '</div>';
    echo '<div class="team-item">';
    echo '<div class="team-name"><a href="https://t.me/GrooSSa" target="_blank" rel="noopener">Мирон Вечный</a></div>';
    echo '<div class="team-role">Куратор вспомогательных структур. Обращаться по вопросам отделов: HR, SMM, Звукорежиссёров и дисциплины внутри радио.</div>';
    echo '<div class="team-item">';
    echo '<div class="team-name">врио <a href="https://t.me/V00KO" target="_blank" rel="noopener">Зайцев</a> и <a href="https://t.me/ti8idi" target="_blank" rel="noopener">Борнитов</a></div>';
    echo '<div class="team-role">Куратор радиовещания. Обращаться по любым вопросам эфиров</div>';
    echo '</div>';
    echo '</div>';
    echo '</div>';
    echo '</div>';

    echo '</div>'; // footer-grid

    // Нижняя строка
    echo '<div class="footer-bottom">';
    echo '<div class="footer-version">Версия ' . htmlspecialchars($version, ENT_QUOTES, 'UTF-8') . ' • Сборка ' . $buildDate . '</div>';
    echo '</div>';
    
    echo '</div>'; // footer-wrapper
    echo '</footer>';
    
    echo '</main>';
    echo '</div>';
    echo '</body></html>';
}

if (!isset($pages[$page])) {
    http_response_code(404);
    $errorPage = __DIR__ . '/../pages/errors.php';
    if (file_exists($errorPage)) {
        $_GET['code'] = '404';
        include $errorPage;
    } else {
        die('Not found');
    }
    exit;
}

if ($page !== 'login' && $page !== 'no_access' && $page !== 'errors' && $page !== 'reg' && $page !== 'api')
    render_header($active);

$pageFile = __DIR__ . $pages[$page];
if (file_exists($pageFile) && is_readable($pageFile)) {
    include $pageFile;
} else {
    http_response_code(500);
    echo "<h1>Ошибка</h1><p>Страница временно недоступна.</p>";
}

if ($page !== 'login' && $page !== 'no_access' && $page !== 'errors' && $page !== 'reg' && $page !== 'api')
    render_footer();
