<?php

declare(strict_types=1);

ini_set('display_errors', '0');
ini_set('log_errors', '1');
date_default_timezone_set('UTC');

const APP_NAME = 'OmniMax Panel Profissional';
const DB_DIR = __DIR__ . '/../storage';
const DB_FILE = DB_DIR . '/omnimax.sqlite';

if (!is_dir(DB_DIR)) {
    @mkdir(DB_DIR, 0750, true);
}

function is_https(): bool
{
    return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
        || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https');
}

function app_base_path(): string
{
    $panelRoot = str_replace('\\', '/', (string)(realpath(__DIR__ . '/..') ?: dirname(__DIR__)));
    $documentRoot = str_replace('\\', '/', (string)(realpath((string)($_SERVER['DOCUMENT_ROOT'] ?? '')) ?: ($_SERVER['DOCUMENT_ROOT'] ?? '')));
    if ($documentRoot !== '' && strpos($panelRoot, rtrim($documentRoot, '/')) === 0) {
        $relative = substr($panelRoot, strlen(rtrim($documentRoot, '/')));
        return $relative === false ? '' : rtrim('/' . ltrim($relative, '/'), '/');
    }
    $script = str_replace('\\', '/', (string)($_SERVER['SCRIPT_NAME'] ?? '/index.php'));
    $dir = rtrim(dirname($script), '/.');
    return $dir === '' ? '' : $dir;
}

function panel_url(string $path = ''): string
{
    $base = app_base_path();
    $path = ltrim($path, '/');
    return ($base === '' ? '' : $base) . '/' . $path;
}

function panel_base_url(): string
{
    $scheme = is_https() ? 'https' : 'http';
    $host = (string)($_SERVER['HTTP_HOST'] ?? 'localhost');
    return $scheme . '://' . $host . app_base_path();
}

function panel_absolute_url(string $path = ''): string
{
    return rtrim(panel_base_url(), '/') . '/' . ltrim($path, '/');
}

function request_path(): string
{
    $path = (string)(parse_url((string)($_SERVER['REQUEST_URI'] ?? '/'), PHP_URL_PATH) ?: '/');
    $base = app_base_path();
    if ($base !== '' && strpos($path, $base) === 0) {
        $path = substr($path, strlen($base));
    }
    if ($path === '' || $path === false) {
        return '/';
    }
    return '/' . ltrim($path, '/');
}

function starts_with(string $haystack, string $needle): bool
{
    return $needle === '' || strncmp($haystack, $needle, strlen($needle)) === 0;
}

$cookiePath = app_base_path() ?: '/';
session_name('omnimax_admin');
session_set_cookie_params([
    'lifetime' => 0,
    'path' => $cookiePath,
    'secure' => is_https(),
    'httponly' => true,
    'samesite' => 'Lax',
]);
if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

function db(): PDO
{
    static $pdo = null;
    if ($pdo instanceof PDO) {
        return $pdo;
    }
    $pdo = new PDO('sqlite:' . DB_FILE);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    $pdo->exec('PRAGMA foreign_keys = ON');
    $pdo->exec('PRAGMA journal_mode = WAL');
    return $pdo;
}

function now(): string
{
    return gmdate('Y-m-d H:i:s');
}

function config_defaults(): array
{
    $buttons = [];
    foreach (['live', 'vod', 'epg', 'series', 'catchup'] as $group) {
        for ($i = 1; $i <= 5; $i++) {
            $buttons['btn_' . $group . ($i === 1 ? '' : (string)$i)] = 'Yes';
        }
    }
    foreach (['radio', 'fav'] as $group) {
        for ($i = 1; $i <= 5; $i++) {
            $buttons['btn_' . $group . ($i === 1 ? '' : (string)$i)] = $group === 'radio' ? 'No' : 'yes';
        }
    }
    $buttons += [
        'btn_account' => 'yes', 'btn_account2' => 'yes', 'btn_account3' => 'yes', 'btn_account4' => 'yes', 'btn_account5' => 'yes',
        'btn_football' => 'yes',
        'btn_pr' => 'no', 'btn_rec' => 'no', 'btn_vpn' => 'no', 'btn_noti' => 'no', 'btn_update' => 'no',
        'btn_login_settings' => 'yes', 'btn_login_account' => 'yes', 'btn_signup' => 'no',
        'ms' => 'no', 'ms2' => 'no', 'ms3' => 'no', 'ms4' => 'no', 'ms5' => 'no',
    ];

    return [
        'core' => [
            'cid' => '1', 'appname' => 'OmniMax', 'status' => 'ACTIVE', 'expire' => '',
            'login_type' => 'xtreamcodes', 'version_code' => '2000', 'filter_status' => 'No',
            'epg_mode' => 'yes', 'apkautoupdate' => 'no', 'show_expire' => 'yes',
            'expiry_popup_enabled' => 'yes',
        ],
        'portal' => [
            'panel' => 'xtreamcodes', 'portal_vod' => 'no', 'portal_series' => 'no',
        ],
        'urls' => [
            'apkurl' => '', 'backupurl' => '', 'logurl' => '', 'activation_url' => 'no',
            'socket_url' => 'ottrun-ws', 'mqtt_url' => '', 'epg_url' => 'No', 'ovpn_url' => 'No',
        ],
        'vpn' => [
            'vpn_enabled' => 'no',
            'vpn_required' => 'no',
            'vpn_auto_connect' => 'no',
            'ovpn_url' => '',
            'ovpn_username' => '',
            'ovpn_password' => '',
            'ovpn_protocol' => 'udp',
            'ovpn_country' => 'RO-FREE#1',
            'vpn_status_text' => 'VPN Proton configurada pelo painel',
        ],
        'support' => [
            'support_email' => '',
            'support_phone' => '',
            'support_text' => 'Escaneie o QR Code ou chame nosso suporte pelo WhatsApp.',
            'support_link' => '',
            'support_qr_url' => '',
        ],
        'branding' => [
            'app_logo_url' => '',
        ],
        'buttons' => $buttons,
        'interface' => [
            'agent' => 'OmniMax', 'all_cat' => 'yes', 'message_enabled' => 'no',
            'announcement_enabled' => 'no', 'updateuserinfo_enabled' => 'no',
            'whatsupcheck_enabled' => 'no', 'login_logo' => 'yes', 'bjob' => 'no',
            'settings_app' => 'yes', 'settings_account' => 'yes', 'logs' => 'no',
            'app_language' => 'en', 'load_last_channel' => 'no', 'admob_banner_id' => 'no',
            'admob_interstitial_id' => 'no', 'show_cat_count' => 'yes', 'send_udid' => 'no',
            'theme' => '2', 'vpn_login_view' => 'no', 'hide_other_login_type' => 'no',
        ],
        'admob' => ['admob_enabled' => 'no'],
        'prebid' => [
            'prebid_enabled' => 'no', 'Host' => '', 'AdUnitId' => '', 'AccountId' => '', 'Banner' => '',
        ],
        'vast' => [
            'vast_enabled' => 'no', 'mid_roll_interval' => '', 'post_roll_start_at' => '',
            'vod_mid_roll_interval' => '', 'vod_pre_roll_url' => '', 'vod_mid_roll_url' => '',
            'vod_post_roll_url' => '', 'series_mid_roll_interval' => '', 'series_pre_roll_url' => '',
            'series_mid_roll_url' => '', 'series_post_roll_url' => '',
        ],
        'ads' => ['freestar' => 'no'],
        'players' => [
            'player' => 'EXO', 'player_tv' => 'EXO', 'player_vod' => 'VLC',
            'player_series' => 'VLC', 'player_catchup' => 'VLC', 'stream_type' => 'ts',
        ],
        'playback' => [
            'vlc_hw' => 'yes', 'last_volume_vlc' => '100', 'plyer_vlc_buffer' => '5000',
            'video_resize_vlc' => '0', 'video_subtiltes_vlc' => 'yes', 'exo_hw' => 'yes',
            'last_volume_exo' => '100', 'plyer_exo_buffer' => '50000', 'video_resize_exo' => '0',
            'video_subtiltes_exo' => 'no',
        ],
        'maintenance' => [
            'mnt_message' => '', 'mnt_status' => 'INACTIVE', 'mnt_expire' => '2099-12-31 23:59:59',
        ],
        'others' => [
            'bg_epg_update' => 'no', 'reset_all_settings' => 'no', 'reset_all_settings_seq' => '1',
            'max_epg_file_size' => '', 'hide_other_login_type' => 'no',
            'hide_recording' => 'no', 'hide_auto_conn_vpn' => 'no',
        ],
        'messages' => [
            'message' => '', 'msgid' => '0', 'msg_status' => 'INACTIVE',
            'msg_expire' => '2099-12-31 23:59:59', 'announcement' => '',
            'ann_status' => 'INACTIVE', 'ann_expire' => '2099-12-31 23:59:59',
            'ann_interval' => '1', 'ann_disappear' => '1', 'whatsup' => 'no',
            'gfilter_status' => 'No', 'filter_json' => '[]', 'category_message' => 'No Messages',
        ],
    ];
}

function migrate(PDO $db): void
{
    $db->exec("CREATE TABLE IF NOT EXISTS admins (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT NOT NULL UNIQUE,
        password_hash TEXT NOT NULL,
        created_at TEXT NOT NULL
    )");
    $db->exec("CREATE TABLE IF NOT EXISTS servers (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        url TEXT NOT NULL UNIQUE,
        active INTEGER NOT NULL DEFAULT 1,
        authorized INTEGER NOT NULL DEFAULT 1,
        priority INTEGER NOT NULL DEFAULT 100,
        created_at TEXT NOT NULL,
        updated_at TEXT NOT NULL,
        last_test_at TEXT,
        last_test_status TEXT,
        last_test_message TEXT
    )");
    $db->exec("CREATE TABLE IF NOT EXISTS devices (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL UNIQUE,
        device_id TEXT,
        dns_id INTEGER,
        dns_name TEXT,
        dns_url TEXT,
        username TEXT,
        password TEXT,
        auto_login INTEGER NOT NULL DEFAULT 0,
        auto_activate INTEGER NOT NULL DEFAULT 0,
        activation_status TEXT NOT NULL DEFAULT 'pending',
        ip_address TEXT,
        user_agent TEXT,
        platform TEXT,
        last_payload TEXT,
        created_at TEXT NOT NULL,
        last_seen_at TEXT NOT NULL
    )");
    $db->exec("CREATE TABLE IF NOT EXISTS app_config (
        section TEXT NOT NULL,
        config_key TEXT NOT NULL,
        config_value TEXT NOT NULL DEFAULT '',
        updated_at TEXT NOT NULL,
        PRIMARY KEY(section, config_key)
    )");

    $stmt = $db->prepare('INSERT OR IGNORE INTO app_config(section,config_key,config_value,updated_at) VALUES(?,?,?,?)');
    foreach (config_defaults() as $section => $items) {
        foreach ($items as $key => $value) {
            $stmt->execute([$section, $key, (string)$value, now()]);
        }
    }

    $columns = [];
    foreach ($db->query('PRAGMA table_info(devices)')->fetchAll() as $column) {
        $columns[(string)$column['name']] = true;
    }
    $addColumns = [
        'device_id' => 'TEXT',
        'dns_id' => 'INTEGER',
        'dns_name' => 'TEXT',
        'dns_url' => 'TEXT',
        'username' => 'TEXT',
        'password' => 'TEXT',
        'auto_login' => 'INTEGER NOT NULL DEFAULT 0',
        'auto_activate' => 'INTEGER NOT NULL DEFAULT 0',
        'activation_status' => "TEXT NOT NULL DEFAULT 'pending'",
        'ip_address' => 'TEXT',
        'user_agent' => 'TEXT',
        'platform' => 'TEXT',
        'last_payload' => 'TEXT',
    ];
    foreach ($addColumns as $name => $definition) {
        if (empty($columns[$name])) {
            $db->exec('ALTER TABLE devices ADD COLUMN ' . $name . ' ' . $definition);
        }
    }
}

migrate(db());

function admin_count(): int
{
    return (int)db()->query('SELECT COUNT(*) FROM admins')->fetchColumn();
}

function is_admin(): bool
{
    return !empty($_SESSION['admin_id']);
}

function require_admin(): void
{
    if (!is_admin()) {
        header('Location: ' . panel_url('index.php'));
        exit;
    }
}

function csrf_token(): string
{
    if (empty($_SESSION['csrf'])) {
        $_SESSION['csrf'] = bin2hex(random_bytes(32));
    }
    return (string)$_SESSION['csrf'];
}

function verify_csrf(): void
{
    $token = (string)($_POST['csrf'] ?? '');
    if (!hash_equals((string)($_SESSION['csrf'] ?? ''), $token)) {
        http_response_code(419);
        exit('Sessão expirada. Atualize a página e tente novamente.');
    }
}

function redirect(string $path): void
{
    header('Location: ' . panel_url($path));
    exit;
}

function e($value): string
{
    return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
}

function flash(string $type, string $message): void
{
    $_SESSION['flash'] = ['type' => $type, 'message' => $message];
}

function pull_flash(): ?array
{
    if (empty($_SESSION['flash'])) {
        return null;
    }
    $flash = $_SESSION['flash'];
    unset($_SESSION['flash']);
    return is_array($flash) ? $flash : null;
}

function get_config(string $section): array
{
    $stmt = db()->prepare('SELECT config_key, config_value FROM app_config WHERE section=?');
    $stmt->execute([$section]);
    $values = [];
    foreach ($stmt->fetchAll() as $row) {
        $values[(string)$row['config_key']] = (string)$row['config_value'];
    }
    return array_merge(config_defaults()[$section] ?? [], $values);
}

function get_config_value(string $section, string $key, string $fallback = ''): string
{
    $values = get_config($section);
    return array_key_exists($key, $values) ? (string)$values[$key] : $fallback;
}

function save_config_section(string $section, array $allowedKeys, array $input): void
{
    $stmt = db()->prepare('INSERT INTO app_config(section,config_key,config_value,updated_at) VALUES(?,?,?,?) ON CONFLICT(section,config_key) DO UPDATE SET config_value=excluded.config_value, updated_at=excluded.updated_at');
    foreach ($allowedKeys as $key) {
        $value = isset($input[$key]) ? trim((string)$input[$key]) : '';
        $stmt->execute([$section, $key, $value, now()]);
    }
}

function save_config_value(string $section, string $key, string $value): void
{
    $stmt = db()->prepare('INSERT INTO app_config(section,config_key,config_value,updated_at) VALUES(?,?,?,?) ON CONFLICT(section,config_key) DO UPDATE SET config_value=excluded.config_value, updated_at=excluded.updated_at');
    $stmt->execute([$section, $key, trim($value), now()]);
}

function normalize_url(string $raw): ?string
{
    $raw = trim($raw);
    if ($raw === '') {
        return null;
    }
    if (!preg_match('#^https?://#i', $raw)) {
        $raw = 'http://' . $raw;
    }
    $parts = parse_url($raw);
    if (!$parts || empty($parts['host'])) {
        return null;
    }
    $scheme = strtolower((string)($parts['scheme'] ?? 'http'));
    if (!in_array($scheme, ['http', 'https'], true)) {
        return null;
    }
    $host = (string)$parts['host'];
    $port = isset($parts['port']) ? ':' . (int)$parts['port'] : '';
    $path = isset($parts['path']) ? rtrim((string)$parts['path'], '/') : '';
    return $scheme . '://' . $host . $port . $path;
}

function normalize_device_id(string $raw): string
{
    $raw = trim($raw);
    if ($raw === '') {
        return '';
    }
    $raw = preg_replace('/\s+/', '', $raw) ?? $raw;
    if (preg_match('/^([0-9a-f]{2}[:-]){5}[0-9a-f]{2}$/i', $raw)) {
        return strtoupper(str_replace('-', ':', $raw));
    }
    if (preg_match('/^[0-9a-f]{12,}$/i', $raw)) {
        $mac = strtoupper(substr($raw, -12));
        return implode(':', str_split($mac, 2));
    }
    return substr($raw, 0, 160);
}

function request_device_id(array $input): string
{
    foreach (['device_id', 'deviceid', 'deviceId', 'mac', 'mac_address', 'macAddress', 'serial', 'udid', 'uuid', 'android_id'] as $key) {
        if (!empty($input[$key])) {
            $id = normalize_device_id((string)$input[$key]);
            if ($id !== '') {
                return $id;
            }
        }
    }
    if (!empty($input['name'])) {
        $name = normalize_device_id((string)$input['name']);
        if (preg_match('/-([A-Za-z0-9:_-]{6,})$/', $name, $match)) {
            $id = normalize_device_id($match[1]);
            if ($id !== '') {
                return $id;
            }
        }
        if ($name !== '') {
            return $name;
        }
    }
    return 'unknown-' . substr(hash('sha256', (string)($_SERVER['REMOTE_ADDR'] ?? '') . '|' . (string)($_SERVER['HTTP_USER_AGENT'] ?? '')), 0, 16);
}

function input_has_device_id(array $input): bool
{
    foreach (['device_id', 'deviceid', 'deviceId', 'mac', 'mac_address', 'macAddress', 'name', 'serial', 'udid', 'uuid', 'android_id'] as $key) {
        if (!empty($input[$key])) {
            return true;
        }
    }
    return false;
}

function panel_flag_value($value, int $default = 0): int
{
    if (is_bool($value)) {
        return $value ? 1 : 0;
    }

    if (is_int($value) || is_float($value)) {
        return ((int)$value) === 1 ? 1 : 0;
    }

    $normalized = strtolower(trim((string)$value));
    if (in_array($normalized, ['1', 'true', 'yes', 'sim', 'on', 'active', 'ativo'], true)) {
        return 1;
    }
    if (in_array($normalized, ['0', 'false', 'no', 'nao', 'não', 'off', 'inactive', 'inativo'], true)) {
        return 0;
    }

    return $default === 1 ? 1 : 0;
}

function find_server_by_id_or_url($id, string $url = ''): ?array
{
    if ((int)$id > 0) {
        $stmt = db()->prepare('SELECT * FROM servers WHERE id = ? LIMIT 1');
        $stmt->execute([(int)$id]);
        $row = $stmt->fetch();
        if ($row) {
            return $row;
        }
    }
    $url = (string)normalize_url($url);
    if ($url !== '') {
        $stmt = db()->prepare('SELECT * FROM servers WHERE url = ? LIMIT 1');
        $stmt->execute([$url]);
        $row = $stmt->fetch();
        if ($row) {
            return $row;
        }
    }
    return null;
}

function upsert_device(array $input): array
{
    $deviceId = request_device_id($input);
    $name = $deviceId !== '' ? $deviceId : normalize_device_id((string)($input['name'] ?? ''));
    if ($name === '') {
        $name = 'unknown-device';
    }

    $server = find_server_by_id_or_url($input['dns_id'] ?? $input['server_id'] ?? 0, (string)($input['dns_url'] ?? $input['server_url'] ?? $input['portal'] ?? ''));
    $dnsId = $server ? (int)$server['id'] : null;
    $dnsName = $server ? (string)$server['name'] : trim((string)($input['dns_name'] ?? $input['server_name'] ?? ''));
    $dnsUrl = $server ? normalize_url((string)$server['url']) : normalize_url((string)($input['dns_url'] ?? $input['server_url'] ?? $input['portal'] ?? ''));

    $existingStmt = db()->prepare('SELECT * FROM devices WHERE name = ? LIMIT 1');
    $existingStmt->execute([$name]);
    $existing = $existingStmt->fetch();

    $username = array_key_exists('username', $input) ? trim((string)$input['username']) : (string)($existing['username'] ?? '');
    $password = array_key_exists('password', $input) ? (string)$input['password'] : (string)($existing['password'] ?? '');
    $autoLogin = array_key_exists('auto_login', $input) ? panel_flag_value($input['auto_login'], (int)($existing['auto_login'] ?? 0)) : (int)($existing['auto_login'] ?? 0);
    $autoActivate = array_key_exists('auto_activate', $input) ? panel_flag_value($input['auto_activate'], (int)($existing['auto_activate'] ?? 0)) : (int)($existing['auto_activate'] ?? 0);
    $activationStatus = array_key_exists('activation_status', $input) ? trim((string)$input['activation_status']) : (string)($existing['activation_status'] ?? '');
    if ($activationStatus === '') {
        $activationStatus = $autoActivate ? 'active' : 'pending';
    }

    $payload = json_encode($input, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    $stmt = db()->prepare(
        'INSERT INTO devices(name,device_id,dns_id,dns_name,dns_url,username,password,auto_login,auto_activate,activation_status,ip_address,user_agent,platform,last_payload,created_at,last_seen_at)
         VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
         ON CONFLICT(name) DO UPDATE SET
            device_id=excluded.device_id,
            dns_id=COALESCE(excluded.dns_id, devices.dns_id),
            dns_name=COALESCE(NULLIF(excluded.dns_name, ""), devices.dns_name),
            dns_url=COALESCE(NULLIF(excluded.dns_url, ""), devices.dns_url),
            username=COALESCE(NULLIF(excluded.username, ""), devices.username),
            password=COALESCE(NULLIF(excluded.password, ""), devices.password),
            auto_login=excluded.auto_login,
            auto_activate=excluded.auto_activate,
            activation_status=excluded.activation_status,
            ip_address=excluded.ip_address,
            user_agent=excluded.user_agent,
            platform=COALESCE(NULLIF(excluded.platform, ""), devices.platform),
            last_payload=excluded.last_payload,
            last_seen_at=excluded.last_seen_at'
    );
    $stmt->execute([
        $name,
        $deviceId,
        $dnsId,
        $dnsName,
        $dnsUrl,
        $username,
        $password,
        $autoLogin,
        $autoActivate,
        $activationStatus,
        (string)($_SERVER['REMOTE_ADDR'] ?? ''),
        substr((string)($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255),
        trim((string)($input['platform'] ?? $input['model'] ?? '')),
        $payload ?: '{}',
        now(),
        now(),
    ]);

    $query = db()->prepare('SELECT * FROM devices WHERE name = ? LIMIT 1');
    $query->execute([$name]);
    return $query->fetch() ?: ['name' => $name, 'device_id' => $deviceId];
}

function device_auto_config(array $device): array
{
    $servers = api_servers();
    $dnsId = (int)($device['dns_id'] ?? 0);
    $dnsUrl = normalize_url((string)($device['dns_url'] ?? ''));
    $dnsName = (string)($device['dns_name'] ?? '');
    if (!$dnsUrl && $servers) {
        $dnsId = (int)$servers[0]['id'];
        $dnsUrl = (string)$servers[0]['url'];
        $dnsName = (string)$servers[0]['name'];
    }

    return [
        'device_id' => (string)($device['device_id'] ?? $device['name'] ?? ''),
        'auto_login' => (int)($device['auto_login'] ?? 0) === 1,
        'auto_activate' => (int)($device['auto_activate'] ?? 0) === 1,
        'activation_status' => (string)($device['activation_status'] ?? 'pending'),
        'dns' => [
            'id' => $dnsId,
            'name' => $dnsName,
            'url' => $dnsUrl ?: '',
        ],
        'username' => (string)($device['username'] ?? ''),
        'password' => (string)($device['password'] ?? ''),
        'vpn' => vpn_config_payload(true),
        'vpn_enabled' => vpn_config_payload(false)['vpn_enabled'],
        'vpn_required' => vpn_config_payload(false)['vpn_required'],
        'vpn_auto_connect' => vpn_config_payload(false)['vpn_auto_connect'],
        'ovpn_url' => vpn_config_payload(false)['vpn_enabled'] ? vpn_effective_url() : 'No',
        'ovpn_username' => vpn_config_payload(false)['vpn_enabled'] ? (string)(get_config('vpn')['ovpn_username'] ?? '') : '',
        'ovpn_password' => vpn_config_payload(false)['vpn_enabled'] ? (string)(get_config('vpn')['ovpn_password'] ?? '') : '',
        'expiry_popup_enabled' => get_config_value('core', 'expiry_popup_enabled', 'yes') === 'yes',
    ];
}

function vpn_effective_url(): string
{
    $vpn = get_config('vpn');
    $url = trim((string)($vpn['ovpn_url'] ?? ''));
    if ($url === '' || strcasecmp($url, 'no') === 0) {
        $url = panel_absolute_url('api/vpn/config.ovpn');
    }
    return $url;
}

function vpn_config_payload(bool $includePassword = true): array
{
    $vpn = get_config('vpn');
    $enabled = strtolower(trim((string)($vpn['vpn_enabled'] ?? 'no'))) === 'yes';
    $required = strtolower(trim((string)($vpn['vpn_required'] ?? 'no'))) === 'yes';
    $auto = strtolower(trim((string)($vpn['vpn_auto_connect'] ?? 'no'))) === 'yes';
    $payload = [
        'vpn_enabled' => $enabled,
        'vpn_required' => $required,
        'vpn_auto_connect' => $auto,
        'ovpn_url' => $enabled ? vpn_effective_url() : 'No',
        'ovpn_username' => $enabled ? (string)($vpn['ovpn_username'] ?? '') : '',
        'ovpn_protocol' => (string)($vpn['ovpn_protocol'] ?? 'udp'),
        'ovpn_country' => (string)($vpn['ovpn_country'] ?? ''),
        'vpn_status_text' => (string)($vpn['vpn_status_text'] ?? ''),
    ];
    if ($includePassword) {
        $payload['ovpn_password'] = $enabled ? (string)($vpn['ovpn_password'] ?? '') : '';
    }
    return $payload;
}

function api_servers(): array
{
    $rows = db()->query('SELECT * FROM servers WHERE active=1 AND authorized=1 ORDER BY priority ASC, name ASC')->fetchAll();
    $out = [];
    foreach ($rows as $row) {
        $url = normalize_url((string)$row['url']);
        if (!$url) {
            continue;
        }
        $out[] = [
            'id' => (int)$row['id'],
            'name' => (string)$row['name'],
            'url' => $url,
            'status' => 'active',
            'priority' => (int)$row['priority'],
        ];
    }
    return $out;
}

function test_dns_connection(string $base): array
{
    $base = (string)normalize_url($base);
    if ($base === '') {
        return ['offline', 'URL invalida'];
    }

    $target = rtrim($base, '/') . '/player_api.php';
    $ch = curl_init($target);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_CONNECTTIMEOUT => 8,
        CURLOPT_TIMEOUT => 14,
        CURLOPT_USERAGENT => 'OmniMax-Panel/1.0',
    ]);
    $body = curl_exec($ch);
    $error = curl_error($ch);
    $code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($body === false) {
        return ['offline', $error !== '' ? $error : 'Sem resposta'];
    }
    if ($code >= 200 && $code < 500) {
        return ['online', 'HTTP ' . $code];
    }
    return ['offline', 'HTTP ' . $code];
}

function support_link_from_config(array $support): string
{
    $link = trim((string)($support['support_link'] ?? ''));
    if ($link !== '') {
        return $link;
    }

    $digits = preg_replace('/\D+/', '', (string)($support['support_phone'] ?? ''));
    if ($digits === '') {
        return panel_absolute_url('support.php');
    }

    $text = trim((string)($support['support_text'] ?? ''));
    return 'https://wa.me/' . $digits . ($text !== '' ? '?text=' . rawurlencode($text) : '');
}

function qr_service_url(string $payload, int $size = 320): string
{
    $safeSize = max(160, min(640, $size));
    return 'https://api.qrserver.com/v1/create-qr-code/?size=' . $safeSize . 'x' . $safeSize . '&data=' . rawurlencode($payload);
}

function allowed_image_extension(string $mime): ?string
{
    return match ($mime) {
        'image/png' => 'png',
        'image/jpeg' => 'jpg',
        'image/webp' => 'webp',
        default => null,
    };
}

function handle_app_logo_upload(string $field = 'app_logo'): ?string
{
    if (empty($_FILES[$field]) || !is_array($_FILES[$field])) {
        return null;
    }

    $file = $_FILES[$field];
    if ((int)($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
        return null;
    }
    if ((int)$file['error'] !== UPLOAD_ERR_OK) {
        throw new RuntimeException('Nao foi possivel receber a imagem enviada.');
    }
    if ((int)$file['size'] > 2 * 1024 * 1024) {
        throw new RuntimeException('A imagem deve ter no maximo 2 MB.');
    }

    $tmp = (string)$file['tmp_name'];
    $info = @getimagesize($tmp);
    if (!$info || empty($info['mime'])) {
        throw new RuntimeException('Envie uma imagem valida em PNG, JPG ou WebP.');
    }
    $ext = allowed_image_extension((string)$info['mime']);
    if ($ext === null) {
        throw new RuntimeException('Formato nao aceito. Use PNG, JPG ou WebP.');
    }

    $dir = __DIR__ . '/../img/app_brand';
    if (!is_dir($dir)) {
        @mkdir($dir, 0755, true);
    }

    $filename = 'app_logo.' . $ext;
    $target = $dir . '/' . $filename;
    if (!move_uploaded_file($tmp, $target)) {
        throw new RuntimeException('Nao foi possivel salvar a imagem.');
    }

    $url = panel_absolute_url('img/app_brand/' . $filename);
    save_config_value('branding', 'app_logo_url', $url);
    return $url;
}

function json_response($data, int $status = 200): void
{
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('X-Content-Type-Options: nosniff');
    echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    exit;
}

function request_data(): array
{
    $data = array_merge($_GET, $_POST);
    $raw = file_get_contents('php://input');
    if (is_string($raw) && $raw !== '') {
        $decoded = json_decode($raw, true);
        if (is_array($decoded)) {
            $data = array_merge($data, $decoded);
        }
    }
    return $data;
}
