<?php
declare(strict_types=1);

/**
 * /admin/_helpers.php
 * Helper-и адмінпанелі:
 * - сесія (safe start)
 * - універсальний escaper e()
 * - визначення мови (uk/ru/en)
 * - fallback-переклади
 * - safe back url (/admin/*)
 * - перевірка таблиць/колонок
 * - безпечні COUNT/SUM
 * - формат байтів
 * - кешований розмір директорії (/upload)
 * - flash повідомлення
 * - helpers для активації користувача (детект колонок + відправка листа)
 */

if (!function_exists('admin_session_start')) {
    function admin_session_start(): void {
        if (session_status() === PHP_SESSION_ACTIVE) return;
        if (headers_sent()) return;
        session_start();
    }
}

/* ===== універсальний escaper для адмінки ===== */
if (!function_exists('e')) {
    function e($v): string {
        if ($v === null) return '';
        if (is_array($v)) {
            $v = json_encode($v, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } elseif (is_object($v)) {
            $v = method_exists($v, '__toString')
                ? (string)$v
                : json_encode($v, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            $v = (string)$v;
        }
        if ($v === false) $v = '';
        return htmlspecialchars((string)$v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }
}

if (!function_exists('admin_lang')) {
    function admin_lang(): string {
        admin_session_start();

        $l = '';
        if (function_exists('lang')) $l = (string)lang();
        if ($l === '') $l = (string)($_SESSION['lang'] ?? '');
        if ($l === '' && function_exists('current_user')) {
            $u = current_user();
            $l = (string)($u['lang'] ?? '');
        }
        if (!in_array($l, ['uk','ru','en'], true)) $l = 'uk';
        return $l;
    }
}

if (!function_exists('admin_tt')) {
    function admin_tt(string $key, string $uk, string $ru, string $en): string {
        if (function_exists('t')) {
            $v = (string)t($key);
            if ($v !== '' && $v !== $key) return $v;
        }
        return match (admin_lang()) {
            'en' => $en,
            'ru' => $ru,
            default => $uk,
        };
    }
}

/* ===== safe back url (/admin/* only) ===== */
if (!function_exists('admin_safe_back')) {
    function admin_safe_back(string $p, string $fallback = '/admin/'): string {
        $p = trim($p);
        if ($p === '') return $fallback;

        if ($p[0] !== '/') return $fallback;
        if (str_contains($p, "\0")) return $fallback;
        if (str_contains($p, '..')) return $fallback;
        if (preg_match('~^//~', $p)) return $fallback;

        if (!preg_match('~^/admin/~', $p)) return $fallback;

        return $p;
    }
}

if (!function_exists('admin_table_exists')) {
    function admin_table_exists(PDO $pdo, string $table): bool {
        static $cache = [];
        $k = 't:' . $table;
        if (array_key_exists($k, $cache)) return (bool)$cache[$k];

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

if (!function_exists('admin_column_exists')) {
    function admin_column_exists(PDO $pdo, string $table, string $col): bool {
        static $cache = [];
        $k = 'c:' . $table . ':' . $col;
        if (array_key_exists($k, $cache)) return (bool)$cache[$k];

        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, $col]);
            $cache[$k] = (bool)$st->fetchColumn();
        } catch (Throwable $e) {
            $cache[$k] = false;
        }
        return (bool)$cache[$k];
    }
}

if (!function_exists('admin_safe_int')) {
    function admin_safe_int(PDO $pdo, string $sql, array $params = []): int {
        try {
            $st = $pdo->prepare($sql);
            $st->execute($params);
            return (int)$st->fetchColumn();
        } catch (Throwable $e) {
            return 0;
        }
    }
}

if (!function_exists('admin_safe_sum')) {
    function admin_safe_sum(PDO $pdo, string $sql, array $params = []): int {
        try {
            $st = $pdo->prepare($sql);
            $st->execute($params);
            $v = $st->fetchColumn();
            return ($v === null) ? 0 : (int)$v;
        } catch (Throwable $e) {
            return 0;
        }
    }
}

if (!function_exists('admin_human_bytes')) {
    function admin_human_bytes(int $bytes): string {
        $b = max(0, $bytes);
        $units = ['B','KB','MB','GB','TB'];
        $i = 0;
        while ($b >= 1024 && $i < count($units) - 1) {
            $b /= 1024;
            $i++;
        }
        $precision = ($i === 0) ? 0 : 2;
        return number_format((float)$b, $precision, '.', ' ') . ' ' . $units[$i];
    }
}

if (!function_exists('admin_cache_path')) {
    function admin_cache_path(string $key): string {
        $safe = preg_replace('~[^a-zA-Z0-9_\-]~', '_', $key);
        return rtrim(sys_get_temp_dir(), '/\\') . '/vmeregi_admin_' . $safe . '.json';
    }
}

if (!function_exists('admin_cache_get')) {
    function admin_cache_get(string $key, int $ttlSeconds): ?array {
        $p = admin_cache_path($key);
        if (!is_file($p)) return null;

        $raw = @file_get_contents($p);
        if ($raw === false || $raw === '') return null;

        $data = json_decode($raw, true);
        if (!is_array($data) || !isset($data['ts'])) return null;

        if ((time() - (int)$data['ts']) > $ttlSeconds) {
            @unlink($p);
            return null;
        }
        return $data;
    }
}

if (!function_exists('admin_cache_set')) {
    function admin_cache_set(string $key, array $data): void {
        $data['ts'] = time();
        $p = admin_cache_path($key);
        @file_put_contents(
            $p,
            json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            LOCK_EX
        );
    }
}

if (!function_exists('admin_dir_size_bytes')) {
    /** @return array{bytes:int, truncated:bool, files:int} */
    function admin_dir_size_bytes(string $path, int $maxFiles = 250000): array {
        $bytes = 0;
        $files = 0;
        $truncated = false;

        if (!is_dir($path)) {
            return ['bytes' => 0, 'truncated' => false, 'files' => 0];
        }

        try {
            $it = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)
            );
            foreach ($it as $f) {
                /** @var SplFileInfo $f */
                if ($f->isFile()) {
                    $bytes += (int)$f->getSize();
                    $files++;
                    if ($files >= $maxFiles) { $truncated = true; break; }
                }
            }
        } catch (Throwable $e) {}

        return ['bytes' => $bytes, 'truncated' => $truncated, 'files' => $files];
    }
}

if (!function_exists('admin_dir_size_cached')) {
    /** @return array{bytes:int, truncated:bool, files:int, cached:bool} */
    function admin_dir_size_cached(string $path, string $cacheKey, int $ttlSeconds = 600): array {
        $c = admin_cache_get($cacheKey, $ttlSeconds);
        if (is_array($c) && isset($c['bytes'], $c['truncated'], $c['files'])) {
            return [
                'bytes' => (int)$c['bytes'],
                'truncated' => (bool)$c['truncated'],
                'files' => (int)$c['files'],
                'cached' => true,
            ];
        }
        $r = admin_dir_size_bytes($path);
        admin_cache_set($cacheKey, $r);
        return [
            'bytes' => (int)$r['bytes'],
            'truncated' => (bool)$r['truncated'],
            'files' => (int)$r['files'],
            'cached' => false,
        ];
    }
}

/* ===== flash ===== */
if (!function_exists('admin_flash_set')) {
    function admin_flash_set(string $type, string $msg): void {
        admin_session_start();
        if (session_status() !== PHP_SESSION_ACTIVE) return;
        $_SESSION['admin_flash'] = ['type' => $type, 'msg' => $msg];
    }
}

if (!function_exists('admin_flash_take')) {
    /** @return array{type:string,msg:string}|null */
    function admin_flash_take(): ?array {
        admin_session_start();
        if (session_status() !== PHP_SESSION_ACTIVE) return null;

        $v = $_SESSION['admin_flash'] ?? null;
        unset($_SESSION['admin_flash']);

        if (!is_array($v) || !isset($v['type'],$v['msg'])) return null;
        return ['type' => (string)$v['type'], 'msg' => (string)$v['msg']];
    }
}

/* ===== activation helpers ===== */
if (!function_exists('admin_user_activation_fields')) {
    /** @return array{active_col:?string, token_col:?string} */
    function admin_user_activation_fields(PDO $pdo): array {
        $activeCandidates = ['is_active','active','email_verified','is_verified','verified'];
        $tokenCandidates  = ['activation_token','verify_token','email_token','email_verify_token','token'];

        $active = null;
        foreach ($activeCandidates as $c) {
            if (admin_column_exists($pdo, 'users', $c)) { $active = $c; break; }
        }

        $token = null;
        foreach ($tokenCandidates as $c) {
            if (admin_column_exists($pdo, 'users', $c)) { $token = $c; break; }
        }

        return ['active_col' => $active, 'token_col' => $token];
    }
}

if (!function_exists('admin_guess_activation_url')) {
    function admin_guess_activation_url(string $token, string $email = ''): string {
        $candidates = [
            '/activate.php',
            '/verify.php',
            '/activation.php',
            '/auth/activate.php',
        ];
        foreach ($candidates as $rel) {
            $fs = __DIR__ . '/../' . ltrim($rel, '/');
            if (is_file($fs)) {
                $q = 'token=' . urlencode($token);
                if ($email !== '') $q .= '&email=' . urlencode($email);
                return $rel . '?' . $q;
            }
        }
        $q = 'token=' . urlencode($token);
        if ($email !== '') $q .= '&email=' . urlencode($email);
        return '/activate.php?' . $q;
    }
}

if (!function_exists('admin_send_activation_email')) {
    /**
     * Повертає true якщо вдалося викликати хоч якийсь відправник.
     * Якщо не знайшли твої mail-функції — поверне false.
     */
    function admin_send_activation_email(array $user, string $token): bool {
        $email = (string)($user['email'] ?? '');
        if ($email === '') return false;

        $url = admin_guess_activation_url($token, $email);

        // 1) якщо у тебе вже є готова функція
        $fnCandidates = [
            'send_activation_email',
            'auth_send_activation_email',
            'mail_send_activation',
            'send_verify_email',
        ];
        foreach ($fnCandidates as $fn) {
            if (function_exists($fn)) {
                try {
                    $res = $fn($email, $token, $url, $user);
                    return ($res === true || $res === 1);
                } catch (Throwable $e) {
                    // try next
                }
            }
        }

        // 2) fallback: PHP mail() (може бути вимкнено)
        $subject = "VMEREGI: activation";
        $body = "Activation link: " . $url;

        $headers = "MIME-Version: 1.0\r\n"
                 . "Content-Type: text/plain; charset=UTF-8\r\n";

        try {
            return @mail($email, $subject, $body, $headers);
        } catch (Throwable $e) {
            return false;
        }
    }
}