<?php
/**
 * running-line — бегущая строка (marquee-баннер) для AP System.
 *
 * Два режима позиционирования (переключатель "sticky" в настройках):
 *
 * - sticky=0 (по умолчанию): блок остаётся в обычном потоке документа.
 *   JS переносит его в начало/конец <body> (см. running-line.js), он
 *   физически раздвигает контент страницы и не может перекрыть
 *   существующие fixed-элементы сайта, т.к. сам не fixed.
 *
 * - sticky=1: блок становится position:fixed и "прилипает" к
 *   верху/низу экрана при скролле. Чтобы не перекрывать контент, JS
 *   резервирует под него место через margin на <body> (высота блока
 *   меряется на лету — текст может переноситься по-разному на мобильных).
 *   Поле "offset" (px) — ручная отстройка от уже существующих
 *   fixed-элементов сайта (например, его собственного sticky-хедера),
 *   которую нельзя определить автоматически.
 */

$cfg = isset($ap_module_config) && is_array($ap_module_config) ? $ap_module_config : array();

/**
 * Проверяет, входит ли текущий путь страницы в список исключений.
 * Каждая строка — либо точный путь ("/news/news1.php"), либо маска
 * со звёздочкой ("/news/*", звёздочка = любое количество любых
 * символов). Пустые строки игнорируются.
 */
if (!function_exists('ap_running_line_page_excluded')) {
    function ap_running_line_page_excluded($currentPath, $rawList)
    {
        $rawList = (string)$rawList;
        if (trim($rawList) === '') {
            return false;
        }

        $lines = preg_split('/\r\n|\r|\n/', $rawList);
        foreach ($lines as $line) {
            $pattern = trim($line);
            if ($pattern === '') {
                continue;
            }
            if (strpos($pattern, '*') !== false) {
                $regex = '#^' . str_replace('\*', '.*', preg_quote($pattern, '#')) . '$#';
                if (preg_match($regex, $currentPath)) {
                    return true;
                }
            } elseif ($pattern === $currentPath) {
                return true;
            }
        }
        return false;
    }
}

$currentPath = isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '';
if ($currentPath === null || $currentPath === false) {
    $currentPath = '';
}
$excludePages = isset($cfg['exclude_pages']) ? $cfg['exclude_pages'] : '';
if (ap_running_line_page_excluded($currentPath, $excludePages)) {
    // Страница в списке исключений — ничего не выводим.
    return;
}

/**
 * Проверяет, попадает ли текущее время сервера в заданный диапазон
 * "ЧЧ:ММ"–"ЧЧ:ММ". Пустые/некорректные значения = "без ограничения".
 * Поддерживает диапазоны через полночь (from > to).
 */
if (!function_exists('ap_running_line_in_time_window')) {
    function ap_running_line_in_time_window($from, $to)
    {
        $from = trim((string)$from);
        $to = trim((string)$to);
        if ($from === '' || $to === '') {
            return true;
        }

        $timeRe = '/^([01]\d|2[0-3]):([0-5]\d)$/';
        if (!preg_match($timeRe, $from) || !preg_match($timeRe, $to)) {
            // Некорректный формат в настройках — не блокируем показ
            // из-за опечатки администратора, просто игнорируем ограничение.
            return true;
        }

        $now = date('H:i');
        if ($from <= $to) {
            return ($now >= $from && $now <= $to);
        }
        // Диапазон через полночь, например 22:00–06:00.
        return ($now >= $from || $now <= $to);
    }
}

/**
 * Проверяет, попадает ли текущий момент в диапазон дат кампании.
 * Значения приходят из <input type="datetime-local"> в формате
 * "YYYY-MM-DDTHH:MM", который strtotime понимает нативно.
 * Пустые/нераспознанные значения = "без ограничения" с этой стороны.
 */
if (!function_exists('ap_running_line_in_schedule')) {
    function ap_running_line_in_schedule($start, $end)
    {
        $start = trim((string)$start);
        $end = trim((string)$end);
        $now = time();

        if ($start !== '') {
            $startTs = strtotime($start);
            if ($startTs !== false && $now < $startTs) {
                return false;
            }
        }
        if ($end !== '') {
            $endTs = strtotime($end);
            if ($endTs !== false && $now > $endTs) {
                return false;
            }
        }
        return true;
    }
}

$timeFrom = isset($cfg['time_from']) ? $cfg['time_from'] : '';
$timeTo = isset($cfg['time_to']) ? $cfg['time_to'] : '';
if (!ap_running_line_in_time_window($timeFrom, $timeTo)) {
    // Вне окна показа по времени суток — ничего не выводим на этой загрузке.
    return;
}

$scheduleStart = isset($cfg['schedule_start']) ? $cfg['schedule_start'] : '';
$scheduleEnd = isset($cfg['schedule_end']) ? $cfg['schedule_end'] : '';
if (!ap_running_line_in_schedule($scheduleStart, $scheduleEnd)) {
    // Вне диапазона дат кампании — ничего не выводим на этой загрузке.
    return;
}

// --- Текст: каждая непустая строка — отдельное сообщение ---
$rawText = isset($cfg['text']) ? (string)$cfg['text'] : '';
$lines = preg_split('/\r\n|\r|\n/', $rawText);
$messages = array();
foreach ($lines as $line) {
    $line = trim($line);
    if ($line !== '') {
        $messages[] = $line;
    }
}

if (empty($messages)) {
    // Нечего показывать — не выводим пустую строку.
    return;
}

$separator = isset($cfg['separator']) && $cfg['separator'] !== '' ? $cfg['separator'] : '•';

$position = isset($cfg['position']) ? $cfg['position'] : 'top';
if (!in_array($position, array('top', 'bottom'), true)) {
    $position = 'top';
}
$style = (isset($cfg['style']) && $cfg['style'] === 'solid') ? 'solid' : 'glass';
$bgColor = (isset($cfg['bg_color']) && $cfg['bg_color'] !== '') ? $cfg['bg_color'] : '#ffffff';
$textColor = (isset($cfg['text_color']) && $cfg['text_color'] !== '') ? $cfg['text_color'] : '#1a1a1a';

$sticky = (isset($cfg['sticky']) ? $cfg['sticky'] : '0') !== '0';
$offset = isset($cfg['offset']) ? (int)$cfg['offset'] : 0;
if ($offset < 0) $offset = 0;
if ($offset > 500) $offset = 500;

$speed = isset($cfg['speed']) ? (int)$cfg['speed'] : 60;
if ($speed < 10) $speed = 10;
if ($speed > 300) $speed = 300;

// Ключи-булевы всегда присутствуют в конфиге благодаря hidden-инпуту
// в админке (module_config[..][key] = "0" или "1"), отсутствие ключа
// трактуем как старую запись/дефолт = включено.
$pauseOnHover = (isset($cfg['pause_on_hover']) ? $cfg['pause_on_hover'] : '1') !== '0';
$closable = (isset($cfg['closable']) ? $cfg['closable'] : '1') !== '0';

$hideAfterCloseDays = isset($cfg['hide_after_close_days']) ? (int)$cfg['hide_after_close_days'] : 1;
if ($hideAfterCloseDays < 0) {
    $hideAfterCloseDays = 0;
}

$maxShowsPerSession = isset($cfg['max_shows_per_session']) ? (int)$cfg['max_shows_per_session'] : 0;
if ($maxShowsPerSession < 0) {
    $maxShowsPerSession = 0;
}

$clickActionType = isset($cfg['click_action_type']) ? $cfg['click_action_type'] : 'none';
if (!in_array($clickActionType, array('none', 'link', 'click_selector', 'insert_text', 'click_and_insert'), true)) {
    $clickActionType = 'none';
}
$clickUrl = isset($cfg['click_url']) ? $cfg['click_url'] : '';
$clickSelector = isset($cfg['click_selector']) ? $cfg['click_selector'] : '';
$insertTextTemplate = isset($cfg['insert_text_template']) && $cfg['insert_text_template'] !== ''
    ? $cfg['insert_text_template']
    : 'Хочу узнать подробнее про: {text}';
$insertTextSelector = isset($cfg['insert_text_selector']) ? $cfg['insert_text_selector'] : '';
$insertTextDelay = isset($cfg['insert_text_delay']) ? (int)$cfg['insert_text_delay'] : 300;
if ($insertTextDelay < 0) $insertTextDelay = 0;
if ($insertTextDelay > 3000) $insertTextDelay = 3000;
// Действие реально включаем только если для выбранного типа заполнены
// соответствующие поля — иначе клик по баннеру ничего не делает.
$clickable = ($clickActionType === 'link' && $clickUrl !== '')
    || ($clickActionType === 'click_selector' && $clickSelector !== '')
    || ($clickActionType === 'insert_text' && $insertTextSelector !== '')
    || ($clickActionType === 'click_and_insert' && $clickSelector !== '' && $insertTextSelector !== '');

$goalClick = isset($cfg['goal_click']) ? trim($cfg['goal_click']) : '';
$goalClickSafe = str_replace('</script', '<\/script', $goalClick);

$goalShow = isset($cfg['goal_show']) ? trim($cfg['goal_show']) : '';
// Не даём вставленному коду разорвать окружающий <script> тег, даже если
// админ случайно вставит в поле что-то вроде "</script>".
$goalShowSafe = str_replace('</script', '<\/script', $goalShow);

$customCss = isset($cfg['custom_css']) ? trim($cfg['custom_css']) : '';
// Поле для точечных правок чужих элементов сайта (например, сдвинуть его
// собственный sticky-хедер вниз на высоту нашей строки). Выводим как есть
// (это CSS, а не текст для экранирования), страхуем только от разрыва тега.
$customCssSafe = str_replace('</style', '<\/style', $customCss);

$version = trim(@file_get_contents(__DIR__ . '/version.txt'));
$cssPath = '/ap_system/modules/running-line/running-line.css';
$jsPath  = '/ap_system/modules/running-line/running-line.js';

// Собираем один "набор" сообщений через разделитель — трек в CSS/JS
// дублируется дважды для бесшовной прокрутки. Разделитель добавляем
// и ПОСЛЕ последнего сообщения тоже — иначе на стыке двух копий (место
// склейки для бесшовной прокрутки) и на стыке повторов, которые JS
// досыпает для коротких текстов, разделителя не будет.
$itemsHtml = '';
foreach ($messages as $i => $msg) {
    if ($i > 0) {
        $itemsHtml .= '<span class="ap-running-line__sep">' . htmlspecialchars($separator) . '</span>';
    }
    $itemsHtml .= '<span class="ap-running-line__item">' . htmlspecialchars($msg) . '</span>';
}
$itemsHtml .= '<span class="ap-running-line__sep">' . htmlspecialchars($separator) . '</span>';
?>
<link rel="stylesheet" href="<?php echo htmlspecialchars($cssPath); ?>?v=<?php echo urlencode($version); ?>">
<?php if ($customCssSafe !== ''): ?>
<style>
<?php echo $customCssSafe; ?>

</style>
<?php endif; ?>
<div id="ap-running-line"
     class="ap-running-line ap-running-line--<?php echo htmlspecialchars($position, ENT_QUOTES); ?> ap-running-line--style-<?php echo htmlspecialchars($style, ENT_QUOTES); ?><?php echo $pauseOnHover ? ' ap-running-line--pause-hover' : ''; ?><?php echo $closable ? ' ap-running-line--has-close' : ''; ?><?php echo $sticky ? ' ap-running-line--sticky' : ''; ?><?php echo $clickable ? ' ap-running-line--clickable' : ''; ?>"
     style="--ap-rl-bg: <?php echo htmlspecialchars($bgColor, ENT_QUOTES); ?>; --ap-rl-text: <?php echo htmlspecialchars($textColor, ENT_QUOTES); ?>; --ap-rl-offset: <?php echo (int)$offset; ?>px;"
     data-position="<?php echo htmlspecialchars($position, ENT_QUOTES); ?>"
     data-sticky="<?php echo $sticky ? '1' : '0'; ?>"
     data-offset="<?php echo (int)$offset; ?>"
     data-speed="<?php echo (int)$speed; ?>"
     data-separator="<?php echo htmlspecialchars($separator, ENT_QUOTES); ?>"
     data-hide-after-close-days="<?php echo (int)$hideAfterCloseDays; ?>"
     data-max-shows-per-session="<?php echo (int)$maxShowsPerSession; ?>"
     data-click-action-type="<?php echo htmlspecialchars($clickable ? $clickActionType : 'none', ENT_QUOTES); ?>"
     data-click-url="<?php echo htmlspecialchars($clickUrl, ENT_QUOTES); ?>"
     data-click-selector="<?php echo htmlspecialchars($clickSelector, ENT_QUOTES); ?>"
     data-insert-text-template="<?php echo htmlspecialchars($insertTextTemplate, ENT_QUOTES); ?>"
     data-insert-text-selector="<?php echo htmlspecialchars($insertTextSelector, ENT_QUOTES); ?>"
     data-insert-text-delay="<?php echo (int)$insertTextDelay; ?>"
     data-banner-text="<?php echo htmlspecialchars($messages[0], ENT_QUOTES); ?>">
    <?php if ($closable): ?>
        <button type="button" class="ap-running-line__close" aria-label="Закрыть">&times;</button>
    <?php endif; ?>
    <div class="ap-running-line__viewport">
        <div class="ap-running-line__track">
            <span class="ap-running-line__set"><?php echo $itemsHtml; ?></span>
            <span class="ap-running-line__set" aria-hidden="true"><?php echo $itemsHtml; ?></span>
        </div>
    </div>
</div>
<script>
window.__apRunningLineGoals = window.__apRunningLineGoals || {};
window.__apRunningLineGoals.onShow = function () {
<?php echo $goalShowSafe; ?>

};
window.__apRunningLineGoals.onClick = function () {
<?php echo $goalClickSafe; ?>

};
</script>
<script src="<?php echo htmlspecialchars($jsPath); ?>?v=<?php echo urlencode($version); ?>" defer></script>
