<?php
declare(strict_types=1);

/**
 * /includes/account_restrictions.php
 * Обмеження акаунтів:
 * - тимчасова заборона на пости / коментарі / приватні повідомлення
 * - перманентний бан (із дозволом залишити доступ до свого профілю/контенту)
 * - автоматичне зняття прострочених тимчасових обмежень
 */

if (!function_exists('ar_t')) {
    function ar_t(string $uk, string $ru, string $en): string
    {
        $lang = function_exists('lang') ? (string)lang() : (string)($_SESSION['lang'] ?? 'uk');
        if (!in_array($lang, ['uk', 'ru', 'en'], true)) {
            $lang = 'uk';
        }

        return match ($lang) {
            'ru' => $ru,
            'en' => $en,
            default => $uk,
        };
    }
}

if (!function_exists('ar_table_exists')) {
    function ar_table_exists(PDO $pdo, string $table): bool
    {
        if (function_exists('db_has_table')) {
            try {
                return (bool)db_has_table($pdo, $table);
            } catch (Throwable $e) {
            }
        }

        try {
            $st = $pdo->prepare("SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ? LIMIT 1");
            $st->execute([$table]);
            return (bool)$st->fetchColumn();
        } catch (Throwable $e) {
            return false;
        }
    }
}

if (!function_exists('ar_column_exists')) {
    function ar_column_exists(PDO $pdo, string $table, string $column): bool
    {
        if (function_exists('db_has_column')) {
            try {
                return (bool)db_has_column($pdo, $table, $column);
            } catch (Throwable $e) {
            }
        }

        try {
            $st = $pdo->prepare("SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ? LIMIT 1");
            $st->execute([$table, $column]);
            return (bool)$st->fetchColumn();
        } catch (Throwable $e) {
            return false;
        }
    }
}

if (!function_exists('ar_ensure_schema')) {
    function ar_ensure_schema(PDO $pdo): void
    {
        static $done = false;
        if ($done) {
            return;
        }

        $pdo->exec("
            CREATE TABLE IF NOT EXISTS `user_account_restrictions` (
              `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
              `user_id` BIGINT UNSIGNED NOT NULL,
              `posts_blocked_until` DATETIME DEFAULT NULL,
              `comments_blocked_until` DATETIME DEFAULT NULL,
              `messages_blocked_until` DATETIME DEFAULT NULL,
              `is_banned_forever` TINYINT(1) NOT NULL DEFAULT 0,
              `reason` TEXT DEFAULT NULL,
              `set_by_user_id` BIGINT UNSIGNED DEFAULT NULL,
              `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
              `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
              PRIMARY KEY (`id`),
              UNIQUE KEY `uniq_user_id` (`user_id`),
              KEY `idx_posts_until` (`posts_blocked_until`),
              KEY `idx_comments_until` (`comments_blocked_until`),
              KEY `idx_messages_until` (`messages_blocked_until`),
              KEY `idx_forever` (`is_banned_forever`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
        ");

        $done = true;
    }
}

if (!function_exists('ar_normalize_datetime')) {
    function ar_normalize_datetime(?string $raw): ?string
    {
        $raw = trim((string)$raw);
        if ($raw === '') {
            return null;
        }

        $raw = str_replace('T', ' ', $raw);
        if (preg_match('~^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$~', $raw)) {
            $raw .= ':00';
        }

        if (!preg_match('~^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$~', $raw)) {
            return null;
        }

        $ts = strtotime($raw);
        if ($ts === false || $ts <= 0) {
            return null;
        }

        return date('Y-m-d H:i:s', $ts);
    }
}

if (!function_exists('ar_datetime_for_input')) {
    function ar_datetime_for_input(?string $raw): string
    {
        $raw = trim((string)$raw);
        if ($raw === '') {
            return '';
        }

        $ts = strtotime($raw);
        if ($ts === false || $ts <= 0) {
            return '';
        }

        return date('Y-m-d\TH:i', $ts);
    }
}

if (!function_exists('ar_format_until')) {
    function ar_format_until(?string $raw): string
    {
        $raw = trim((string)$raw);
        if ($raw === '') {
            return '';
        }

        $ts = strtotime($raw);
        if ($ts === false || $ts <= 0) {
            return $raw;
        }

        return date('d.m.Y H:i', $ts);
    }
}

if (!function_exists('ar_fetch_row')) {
    function ar_fetch_row(PDO $pdo, int $userId): ?array
    {
        ar_ensure_schema($pdo);

        $st = $pdo->prepare("SELECT * FROM user_account_restrictions WHERE user_id = ? LIMIT 1");
        $st->execute([$userId]);
        $row = $st->fetch(PDO::FETCH_ASSOC) ?: null;
        if (!$row) {
            return null;
        }

        return ar_cleanup_expired($pdo, $row);
    }
}

if (!function_exists('ar_cleanup_expired')) {
    function ar_cleanup_expired(PDO $pdo, array $row): ?array
    {
        $userId = (int)($row['user_id'] ?? 0);
        if ($userId <= 0) {
            return null;
        }

        $now = time();
        $changed = false;

        foreach (['posts_blocked_until', 'comments_blocked_until', 'messages_blocked_until'] as $col) {
            $raw = trim((string)($row[$col] ?? ''));
            if ($raw === '') {
                $row[$col] = null;
                continue;
            }

            $ts = strtotime($raw);
            if ($ts === false || $ts <= 0 || $ts <= $now) {
                $row[$col] = null;
                $changed = true;
            }
        }

        $row['reason'] = trim((string)($row['reason'] ?? ''));
        $row['is_banned_forever'] = (int)($row['is_banned_forever'] ?? 0) === 1 ? 1 : 0;

        $hasAny = ($row['is_banned_forever'] === 1)
            || !empty($row['posts_blocked_until'])
            || !empty($row['comments_blocked_until'])
            || !empty($row['messages_blocked_until']);

        if ($changed) {
            if (!$hasAny) {
                $st = $pdo->prepare("DELETE FROM user_account_restrictions WHERE user_id = ? LIMIT 1");
                $st->execute([$userId]);
                return null;
            }

            $st = $pdo->prepare("UPDATE user_account_restrictions SET posts_blocked_until = ?, comments_blocked_until = ?, messages_blocked_until = ?, updated_at = NOW() WHERE user_id = ? LIMIT 1");
            $st->execute([
                $row['posts_blocked_until'],
                $row['comments_blocked_until'],
                $row['messages_blocked_until'],
                $userId,
            ]);
        }

        return $hasAny ? $row : null;
    }
}

if (!function_exists('ar_get_state')) {
    function ar_get_state(PDO $pdo, int $userId): array
    {
        $empty = [
            'user_id' => $userId,
            'ban_forever' => false,
            'posts_until' => null,
            'comments_until' => null,
            'messages_until' => null,
            'reason' => '',
            'has_any' => false,
            'items' => [],
        ];

        if ($userId <= 0) {
            return $empty;
        }

        $row = ar_fetch_row($pdo, $userId);
        if (!$row) {
            return $empty;
        }

        $state = [
            'user_id' => $userId,
            'ban_forever' => (int)($row['is_banned_forever'] ?? 0) === 1,
            'posts_until' => trim((string)($row['posts_blocked_until'] ?? '')) ?: null,
            'comments_until' => trim((string)($row['comments_blocked_until'] ?? '')) ?: null,
            'messages_until' => trim((string)($row['messages_blocked_until'] ?? '')) ?: null,
            'reason' => trim((string)($row['reason'] ?? '')),
            'has_any' => false,
            'items' => [],
        ];

        if ($state['posts_until']) {
            $state['items'][] = [
                'key' => 'posts',
                'label' => ar_t('Публікація постів', 'Публикация постов', 'Posting'),
                'until' => $state['posts_until'],
                'until_fmt' => ar_format_until($state['posts_until']),
            ];
        }
        if ($state['comments_until']) {
            $state['items'][] = [
                'key' => 'comments',
                'label' => ar_t('Коментарі', 'Комментарии', 'Comments'),
                'until' => $state['comments_until'],
                'until_fmt' => ar_format_until($state['comments_until']),
            ];
        }
        if ($state['messages_until']) {
            $state['items'][] = [
                'key' => 'messages',
                'label' => ar_t('Приватні повідомлення', 'Личные сообщения', 'Private messages'),
                'until' => $state['messages_until'],
                'until_fmt' => ar_format_until($state['messages_until']),
            ];
        }

        $state['has_any'] = $state['ban_forever'] || !empty($state['items']);
        return $state;
    }
}

if (!function_exists('ar_is_staff_can_manage')) {
    function ar_is_staff_can_manage(?array $user): bool
    {
        if (!is_array($user)) {
            return false;
        }

        $role = trim((string)($user['role'] ?? ''));
        return in_array($role, ['admin', 'moderator'], true);
    }
}

if (!function_exists('ar_is_action_blocked')) {
    function ar_is_action_blocked(array $state, string $action): bool
    {
        if (($state['ban_forever'] ?? false) === true) {
            return true;
        }

        return match ($action) {
            'posts' => !empty($state['posts_until']),
            'comments' => !empty($state['comments_until']),
            'messages' => !empty($state['messages_until']),
            default => false,
        };
    }
}

if (!function_exists('ar_action_error')) {
    function ar_action_error(array $state, string $action): string
    {
        $reason = trim((string)($state['reason'] ?? ''));
        $reasonPart = $reason !== ''
            ? ' ' . ar_t('Причина', 'Причина', 'Reason') . ': ' . $reason
            : '';

        if (($state['ban_forever'] ?? false) === true) {
            return ar_t(
                'Ваш акаунт заблоковано назавжди. Вам доступний лише ваш профіль і ваш контент для завантаження.',
                'Ваш аккаунт заблокирован навсегда. Вам доступен только ваш профиль и ваш контент для скачивания.',
                'Your account is permanently blocked. Only your profile and your content download remain available.'
            ) . $reasonPart;
        }

        $until = '';
        if ($action === 'posts') {
            $until = ar_format_until((string)($state['posts_until'] ?? ''));
            $msg = ar_t('Вам тимчасово заборонено публікувати пости', 'Вам временно запрещено публиковать посты', 'You are temporarily not allowed to create posts');
        } elseif ($action === 'comments') {
            $until = ar_format_until((string)($state['comments_until'] ?? ''));
            $msg = ar_t('Вам тимчасово заборонено писати коментарі', 'Вам временно запрещено писать комментарии', 'You are temporarily not allowed to comment');
        } else {
            $until = ar_format_until((string)($state['messages_until'] ?? ''));
            $msg = ar_t('Вам тимчасово заборонено надсилати приватні повідомлення', 'Вам временно запрещено отправлять личные сообщения', 'You are temporarily not allowed to send private messages');
        }

        if ($until !== '') {
            $msg .= ' ' . ar_t('до', 'до', 'until') . ' ' . $until . '.';
        } else {
            $msg .= '.';
        }

        return $msg . $reasonPart;
    }
}

if (!function_exists('ar_set_state')) {
    function ar_set_state(PDO $pdo, int $targetUserId, array $data, int $actorUserId = 0): array
    {
        ar_ensure_schema($pdo);

        $postsUntil = ar_normalize_datetime($data['posts_blocked_until'] ?? null);
        $commentsUntil = ar_normalize_datetime($data['comments_blocked_until'] ?? null);
        $messagesUntil = ar_normalize_datetime($data['messages_blocked_until'] ?? null);
        $banForever = !empty($data['is_banned_forever']) ? 1 : 0;
        $reason = trim((string)($data['reason'] ?? ''));
        if (function_exists('mb_substr')) {
            $reason = (string)mb_substr($reason, 0, 2000, 'UTF-8');
        } else {
            $reason = substr($reason, 0, 2000);
        }

        $hasAny = $banForever === 1 || $postsUntil || $commentsUntil || $messagesUntil;
        if (!$hasAny) {
            $st = $pdo->prepare("DELETE FROM user_account_restrictions WHERE user_id = ? LIMIT 1");
            $st->execute([$targetUserId]);
            return ar_get_state($pdo, $targetUserId);
        }

        $sql = "
            INSERT INTO user_account_restrictions
                (user_id, posts_blocked_until, comments_blocked_until, messages_blocked_until, is_banned_forever, reason, set_by_user_id, created_at, updated_at)
            VALUES
                (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
            ON DUPLICATE KEY UPDATE
                posts_blocked_until = VALUES(posts_blocked_until),
                comments_blocked_until = VALUES(comments_blocked_until),
                messages_blocked_until = VALUES(messages_blocked_until),
                is_banned_forever = VALUES(is_banned_forever),
                reason = VALUES(reason),
                set_by_user_id = VALUES(set_by_user_id),
                updated_at = NOW()
        ";

        $st = $pdo->prepare($sql);
        $st->execute([
            $targetUserId,
            $postsUntil,
            $commentsUntil,
            $messagesUntil,
            $banForever,
            $reason !== '' ? $reason : null,
            $actorUserId > 0 ? $actorUserId : null,
        ]);

        return ar_get_state($pdo, $targetUserId);
    }
}

if (!function_exists('ar_can_access_when_permanent_ban')) {
    function ar_can_access_when_permanent_ban(string $path): bool
    {
        $path = (string)parse_url($path, PHP_URL_PATH);
        if ($path === '') {
            $path = '/';
        }

        $alwaysAllowed = [
            '/profile',
            '/profile/',
            '/profile/index.php',
            '/logout.php',
            '/set_lang.php',
        ];

        if (in_array($path, $alwaysAllowed, true)) {
            return true;
        }

        $prefixes = [
            '/functional/albums/',
            '/functional/audio/',
            '/functional/video/',
            '/upload/',
            '/assets/',
        ];

        foreach ($prefixes as $prefix) {
            if (str_starts_with($path, $prefix)) {
                return true;
            }
        }

        return false;
    }
}

if (!function_exists('ar_should_redirect_permanent_ban')) {
    function ar_should_redirect_permanent_ban(array $state, string $path, bool $isAjax, string $method): bool
    {
        if (($state['ban_forever'] ?? false) !== true) {
            return false;
        }

        if ($isAjax) {
            return false;
        }

        $method = strtoupper(trim($method));
        if ($method !== 'GET' && $method !== 'HEAD') {
            return false;
        }

        return !ar_can_access_when_permanent_ban($path);
    }
}

if (!function_exists('ar_build_notice')) {
    function ar_build_notice(array $state): array
    {
        $items = [];
        foreach ((array)($state['items'] ?? []) as $item) {
            $label = trim((string)($item['label'] ?? ''));
            $until = trim((string)($item['until_fmt'] ?? ''));
            if ($label === '') {
                continue;
            }

            $items[] = $label . ($until !== '' ? ' — ' . ar_t('до', 'до', 'until') . ' ' . $until : '');
        }

        $reason = trim((string)($state['reason'] ?? ''));

        if (($state['ban_forever'] ?? false) === true) {
            return [
                'has_any' => true,
                'title' => ar_t('Акаунт заблоковано', 'Аккаунт заблокирован', 'Account blocked'),
                'text' => ar_t(
                    'Ваш акаунт заблоковано назавжди. Вам доступний лише ваш профіль і ваш контент для завантаження.',
                    'Ваш аккаунт заблокирован навсегда. Вам доступен только ваш профиль и ваш контент для скачивания.',
                    'Your account is permanently blocked. Only your profile and your content download remain available.'
                ),
                'items' => $items,
                'reason' => $reason,
            ];
        }

        return [
            'has_any' => !empty($items),
            'title' => ar_t('Обмеження акаунта', 'Ограничения аккаунта', 'Account restrictions'),
            'text' => ar_t(
                'Для вашого акаунта діють такі тимчасові обмеження:',
                'Для вашего аккаунта действуют такие временные ограничения:',
                'The following temporary restrictions are active for your account:'
            ),
            'items' => $items,
            'reason' => $reason,
        ];
    }
}
