<?php
require_once __DIR__ . '/_device_access.php';
require_once dirname(__DIR__) . '/includes/branding.php';

function auth_json_out(array $arr): void {
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function auth_normalize_mac(?string $mac): string {
    $clean = strtoupper(substr(preg_replace('/[^A-Fa-f0-9]/', '', trim((string)$mac)), 0, 12));
    if (strlen($clean) !== 12) {
        return $clean;
    }
    return implode(':', str_split($clean, 2));
}

function auth_column_exists(PDO $db, string $table, string $column): bool {
    try {
        $st = $db->query("PRAGMA table_info($table)");
        while ($row = $st->fetch(PDO::FETCH_ASSOC)) {
            if (($row['name'] ?? '') === $column) {
                return true;
            }
        }
    } catch (Throwable $e) {
    }
    return false;
}

function auth_table_exists(PDO $db, string $table): bool {
    try {
        $st = $db->prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=? LIMIT 1");
        $st->execute([$table]);
        return (bool)$st->fetch(PDO::FETCH_ASSOC);
    } catch (Throwable $e) {
        return false;
    }
}

function auth_ensure_schema(PDO $db): void {
    da_ensure_schema($db);
    try {
        $db->exec("CREATE TABLE IF NOT EXISTS device_pending_info (
            mac TEXT PRIMARY KEY,
            device_type TEXT NOT NULL DEFAULT 'tv',
            device_name TEXT NOT NULL DEFAULT '',
            device_brand TEXT NOT NULL DEFAULT '',
            device_model TEXT NOT NULL DEFAULT '',
            android_version TEXT NOT NULL DEFAULT '',
            app_version TEXT NOT NULL DEFAULT '',
            android_id TEXT NOT NULL DEFAULT '',
            pending_reason TEXT NOT NULL DEFAULT '',
            created_at INTEGER NOT NULL DEFAULT (strftime('%s','now')),
            updated_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
        )");
        $db->exec("CREATE INDEX IF NOT EXISTS idx_device_pending_info_updated ON device_pending_info(updated_at DESC)");
    } catch (Throwable $e) {
    }

    // Configurações gerais consumidas pelos aplicativos TV e celular.
    try {
        $db->exec("CREATE TABLE IF NOT EXISTS app_config (id INTEGER PRIMARY KEY, updated_at DATETIME)");
        $columns = [
            'tmdb_api_key' => "TEXT NOT NULL DEFAULT 'c310cc4de1212d28e9b2847d519177a9'",
            'sports_api_url' => "TEXT NOT NULL DEFAULT 'https://fut.thefull.site/jogos'",
            'app_language' => "TEXT NOT NULL DEFAULT 'pt_BR'",
            'language_revision' => "TEXT NOT NULL DEFAULT ''",
            'general_config_updated_at' => "DATETIME",
            'p2p_node_url' => "TEXT NOT NULL DEFAULT ''",
            'p2p_node_key' => "TEXT NOT NULL DEFAULT ''",
            'p2p_updated_at' => "DATETIME",
        ];
        foreach ($columns as $column => $definition) {
            if (!auth_column_exists($db, 'app_config', $column)) {
                $db->exec("ALTER TABLE app_config ADD COLUMN {$column} {$definition}");
            }
        }
        $db->exec("INSERT OR IGNORE INTO app_config (id) VALUES (1)");
        $db->exec("UPDATE app_config SET tmdb_api_key = 'c310cc4de1212d28e9b2847d519177a9' WHERE id = 1 AND trim(COALESCE(tmdb_api_key, '')) = ''");
        $db->exec("UPDATE app_config SET sports_api_url = 'https://fut.thefull.site/jogos' WHERE id = 1 AND trim(COALESCE(sports_api_url, '')) = ''");
        $db->exec("UPDATE app_config SET app_language = 'pt_BR' WHERE id = 1 AND trim(COALESCE(app_language, '')) = ''");
        $db->exec("UPDATE app_config SET language_revision = CAST(strftime('%s','now') AS TEXT) WHERE id = 1 AND trim(COALESCE(language_revision, '')) = ''");
        $db->exec("UPDATE app_config SET general_config_updated_at = datetime('now') WHERE id = 1 AND general_config_updated_at IS NULL");
    } catch (Throwable $e) {
    }
}


function auth_get_dns_list(PDO $db): array {
    $dns = [];
    try {
        $queries = ["SELECT url FROM dns ORDER BY nome ASC"];
        try {
            $exists = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='revendedor_dns'")->fetchColumn();
            if ($exists) {
                $queries[] = "SELECT url FROM revendedor_dns ORDER BY nome ASC";
            }
        } catch (Throwable $e) {}
        foreach ($queries as $sql) {
            $st = $db->query($sql);
            while ($row = $st->fetch(PDO::FETCH_ASSOC)) {
                $url = auth_normalize_dns((string)($row['url'] ?? ''));
                if ($url !== '' && !in_array($url, $dns, true)) {
                    $dns[] = $url;
                }
            }
        }
    } catch (Throwable $e) {
    }
    return $dns;
}

function auth_normalize_dns(?string $dns): string {
    $dns = trim((string)$dns);
    if ($dns === '') return '';
    if (!preg_match('~^https?://~i', $dns)) {
        $dns = 'http://' . $dns;
    }
    return rtrim($dns, '/');
}

function auth_xtream_blocked_status(?string $status): bool {
    $s = strtolower(trim((string)$status));
    if ($s === '') return false;
    foreach (['disabled', 'disable', 'banned', 'ban', 'expired', 'expirado', 'blocked', 'bloqueado'] as $bad) {
        if (strpos($s, $bad) !== false) return true;
    }
    return false;
}

function auth_fetch_json_url(string $url, int $timeout = 12): ?array {
    $response = false;
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CONNECTTIMEOUT => 6,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_USERAGENT => 'TheFull-Auth/1.0',
        ]);
        $response = curl_exec($ch);
        curl_close($ch);
    } else {
        $ctx = stream_context_create([
            'http' => ['timeout' => $timeout, 'header' => "User-Agent: TheFull-Auth/1.0\r\n"],
            'ssl' => ['verify_peer' => false, 'verify_peer_name' => false],
        ]);
        $response = @file_get_contents($url, false, $ctx);
    }
    if (!is_string($response) || trim($response) === '') return null;
    $json = json_decode($response, true);
    return is_array($json) ? $json : null;
}

function auth_validate_xtream_credentials(string $dns, string $username, string $password): array {
    $dns = auth_normalize_dns($dns);
    $username = trim($username);
    $password = trim($password);
    $base = [
        'ok' => false,
        'expired' => false,
        'dns' => $dns,
        'exp' => 0,
        'message' => 'Usuário, senha ou DNS inválidos.',
        'user_info' => [],
    ];
    if ($dns === '' || $username === '' || $password === '') {
        $base['message'] = 'missing_credentials';
        return $base;
    }
    $url = $dns . '/player_api.php?username=' . urlencode($username) . '&password=' . urlencode($password);
    $json = auth_fetch_json_url($url, 12);
    if (!is_array($json) || !isset($json['user_info']) || !is_array($json['user_info'])) {
        $base['message'] = 'invalid_json';
        return $base;
    }
    $info = $json['user_info'];
    $base['user_info'] = $info;
    $auth = (int)($info['auth'] ?? 0);
    if ($auth !== 1) {
        $base['message'] = 'auth_failed';
        return $base;
    }
    $status = (string)($info['status'] ?? '');
    if (auth_xtream_blocked_status($status)) {
        $base['expired'] = stripos($status, 'expired') !== false || stripos($status, 'expirado') !== false;
        $base['message'] = $base['expired'] ? 'expired' : 'account_blocked';
        return $base;
    }
    $exp = (int)($info['exp_date'] ?? 0);
    if ($exp > 0 && $exp < time()) {
        $base['expired'] = true;
        $base['exp'] = $exp;
        $base['message'] = 'expired';
        return $base;
    }
    $base['ok'] = true;
    $base['expired'] = false;
    $base['exp'] = max(0, $exp);
    $base['message'] = 'ok';
    return $base;
}

function auth_validate_dns_credentials(array $dnsList, string $username, string $password, string $dnsSelected = ''): array {
    $ordered = [];
    $selected = auth_normalize_dns($dnsSelected);
    if ($selected !== '') $ordered[] = $selected;
    foreach ($dnsList as $dns) {
        $d = auth_normalize_dns((string)$dns);
        if ($d !== '' && !in_array($d, $ordered, true)) $ordered[] = $d;
    }
    $last = [
        'ok' => false,
        'expired' => false,
        'dns' => $selected,
        'exp' => 0,
        'message' => 'dns_empty',
        'user_info' => [],
    ];
    foreach ($ordered as $dns) {
        $res = auth_validate_xtream_credentials($dns, $username, $password);
        if (!empty($res['ok']) || !empty($res['expired'])) return $res;
        $last = $res;
    }
    return $last;
}

function auth_get_active_login_mode(PDO $db): string {
    try {
        $st = $db->query("SELECT active_login_mode FROM app_config WHERE id = 1 LIMIT 1");
        $mode = strtolower(trim((string)$st->fetchColumn()));
    } catch (Throwable $e) {
        $mode = 'normal';
    }
    if (!in_array($mode, ['normal', 'mac', 'activation_code'], true)) {
        $mode = 'normal';
    }
    return $mode;
}

function auth_get_test_config(PDO $db): array {
    try {
        $row = $db->query("SELECT * FROM config_test WHERE id = 1 LIMIT 1")
            ->fetch(PDO::FETCH_ASSOC);
        return is_array($row) ? $row : [];
    } catch (Throwable $e) {
        return [];
    }
}

function auth_get_app_flags(PDO $db): array {
    try {
        $row = $db->query("SELECT qrcode_app_enabled, renew_button_enabled, test_button_enabled, vencimento_modal_enabled FROM app_config WHERE id = 1 LIMIT 1")->fetch(PDO::FETCH_ASSOC);
        if (!is_array($row)) return ['qrcode_app_enabled' => 1, 'renew_button_enabled' => 1, 'test_button_enabled' => 1, 'vencimento_modal_enabled' => 1];
        return [
            'qrcode_app_enabled' => (int)($row['qrcode_app_enabled'] ?? 1),
            'renew_button_enabled' => (int)($row['renew_button_enabled'] ?? 1),
            'test_button_enabled' => (int)($row['test_button_enabled'] ?? 1),
            'vencimento_modal_enabled' => (int)($row['vencimento_modal_enabled'] ?? 1),
        ];
    } catch (Throwable $e) {
        return ['qrcode_app_enabled' => 1, 'renew_button_enabled' => 1, 'test_button_enabled' => 1, 'vencimento_modal_enabled' => 1];
    }
}

function auth_get_p2p_node_config(PDO $db): array {
    $defaults = [
        'p2p_node_url' => '',
        'p2p_node_key' => '',
        'p2p_updated_at' => '',
        'configured' => false,
    ];
    try {
        $row = $db->query("SELECT p2p_node_url, p2p_node_key, p2p_updated_at FROM app_config WHERE id = 1 LIMIT 1")->fetch(PDO::FETCH_ASSOC);
        if (!is_array($row)) return $defaults;
        $url = rtrim(trim((string)($row['p2p_node_url'] ?? '')), '/');
        if ($url !== '' && !preg_match('~^https?://[^/\s]+$~i', $url)) $url = '';
        $key = trim((string)($row['p2p_node_key'] ?? ''));
        if (strlen($key) < 24 || preg_match('/\s/', $key)) $key = '';
        return [
            'p2p_node_url' => $url,
            'p2p_node_key' => $key,
            'p2p_updated_at' => (string)($row['p2p_updated_at'] ?? ''),
            'configured' => $url !== '' && $key !== '',
        ];
    } catch (Throwable $e) {
        return $defaults;
    }
}

function auth_get_general_app_config(PDO $db): array {
    $defaults = [
        'tmdb_api_key' => 'c310cc4de1212d28e9b2847d519177a9',
        'sports_api_url' => 'https://fut.thefull.site/jogos',
        'app_language' => 'pt_BR',
        'language_revision' => '',
        'general_config_updated_at' => '',
    ];
    try {
        $row = $db->query("SELECT tmdb_api_key, sports_api_url, app_language, language_revision, general_config_updated_at FROM app_config WHERE id = 1 LIMIT 1")->fetch(PDO::FETCH_ASSOC);
        if (!is_array($row)) return $defaults;
        $key = trim((string)($row['tmdb_api_key'] ?? ''));
        if (!preg_match('/^[a-f0-9]{32}$/i', $key)) $key = $defaults['tmdb_api_key'];
        $sports = rtrim(trim((string)($row['sports_api_url'] ?? '')), '/');
        if (!preg_match('~^https?://[^\s]+$~i', $sports)) $sports = $defaults['sports_api_url'];
        $language = trim((string)($row['app_language'] ?? 'pt_BR'));
        if (!in_array($language, ['pt_BR', 'en', 'es'], true)) $language = 'pt_BR';
        return [
            'tmdb_api_key' => $key,
            'sports_api_url' => $sports,
            'app_language' => $language,
            'language_revision' => trim((string)($row['language_revision'] ?? '')),
            'general_config_updated_at' => (string)($row['general_config_updated_at'] ?? ''),
        ];
    } catch (Throwable $e) {
        return $defaults;
    }
}

function auth_ensure_user_activation_code(PDO $db, array &$userRow): string {
    $code = trim((string)($userRow['activation_code'] ?? ''));
    $mac = auth_normalize_mac((string)($userRow['mac'] ?? ''));
    if ($code !== '' || $mac === '') return $code;
    $code = auth_generate_activation_code($db);
    try {
        $st = $db->prepare("UPDATE usuarios SET activation_code = ? WHERE mac = ?");
        $st->execute([$code, $mac]);
        $userRow['activation_code'] = $code;
    } catch (Throwable $e) {}
    return $code;
}

function auth_generate_activation_code(PDO $db): string {
    do {
        $code = str_pad((string)random_int(0, 9999), 4, '0', STR_PAD_LEFT);
        $st = $db->prepare("SELECT COUNT(*) FROM usuarios WHERE activation_code = ?");
        $st->execute([$code]);
        $exists = (int)$st->fetchColumn() > 0;
        $st->closeCursor();
    } while ($exists);
    return $code;
}

function auth_user_has_credentials(array $userRow): bool {
    return trim((string)($userRow['dns'] ?? '')) !== ''
        && trim((string)($userRow['username'] ?? '')) !== ''
        && trim((string)($userRow['password'] ?? '')) !== '';
}

function auth_format_exp($exp): string {
    $exp = (int)$exp;
    return $exp > 0 ? date('Y-m-d H:i:s', $exp) : '';
}

function auth_parse_vencimento_to_timestamp($value): int {
    if (is_numeric($value)) return (int)$value;
    $raw = trim((string)$value);
    if ($raw === '') return 0;
    $ts = strtotime($raw);
    return $ts ? (int)$ts : 0;
}

function auth_ensure_pending_mac(PDO $db, string $mac, string $deviceType = 'tv'): ?array {
    $mac = auth_normalize_mac($mac);
    if ($mac === '' || strlen(str_replace(':', '', $mac)) !== 12) return null;
    $deviceType = da_normalize_device_type($deviceType);
    $st = $db->prepare('SELECT * FROM usuarios WHERE mac = ? LIMIT 1');
    $st->execute([$mac]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    $st->closeCursor();
    if ($row) return $row;

    $cols = [];
    $q = $db->query('PRAGMA table_info(usuarios)');
    while ($r = $q->fetch(PDO::FETCH_ASSOC)) $cols[] = (string)$r['name'];
    if (!in_array('mac', $cols, true)) return null;
    $fields = ['mac'];
    $values = [$mac];
    $add = function(string $col, $val) use (&$fields, &$values, $cols): void {
        if (in_array($col, $cols, true)) { $fields[] = $col; $values[] = $val; }
    };
    $add('dns', '');
    $add('username', '');
    $add('password', '');
    $add('vencimento', '');
    $add('status', 'aguardando');
    $add('nome_cliente', 'Cliente ' . strtoupper(substr(str_replace(':', '', $mac), -4)));
    $add('whatsapp', '');
    $add('teste', 0);
    $add('teste_criado_at', 0);
    $add('login_mode', 'mac');
    $add('device_type', $deviceType);
    $add('last_device_type', $deviceType);
    $add('usuario_id', 0);
    $add('activation_code', auth_generate_activation_code($db));
    $placeholders = implode(',', array_fill(0, count($fields), '?'));
    $sql = 'INSERT OR IGNORE INTO usuarios (' . implode(',', $fields) . ') VALUES (' . $placeholders . ')';
    $execPending = function() use ($db, $sql, $values) {
        $stmt = $db->prepare($sql);
        $ok = $stmt->execute($values);
        $stmt->closeCursor();
        return $ok;
    };
    if (function_exists('trial_db_exec_retry')) {
        trial_db_exec_retry($execPending, 8, 200);
    } else {
        $execPending();
    }
    $st = $db->prepare('SELECT * FROM usuarios WHERE mac = ? LIMIT 1');
    $st->execute([$mac]);
    $saved = $st->fetch(PDO::FETCH_ASSOC) ?: null;
    $st->closeCursor();
    return $saved;
}


function auth_pending_meta_value(array $meta, string $key, int $maxLen = 180): string {
    $value = trim((string)($meta[$key] ?? ''));
    if ($value === '') return '';
    if (function_exists('mb_substr')) return mb_substr($value, 0, $maxLen);
    return substr($value, 0, $maxLen);
}

/**
 * Registra ou atualiza um aparelho pendente sem apagar um acesso válido por engano.
 *
 * - $clearCredentials=true: zera DNS/usuário/senha, remove os servidores e coloca
 *   o MAC novamente como aguardando ativação.
 * - $clearCredentials=false: apenas cria o MAC quando ele não existe e atualiza
 *   os metadados do aparelho. Se já estiver ativo, preserva as credenciais.
 */
function auth_upsert_pending_device(
    PDO $db,
    string $mac,
    string $deviceType = 'tv',
    array $meta = [],
    bool $clearCredentials = false,
    string $reason = ''
): ?array {
    auth_ensure_schema($db);
    $mac = auth_normalize_mac($mac);
    if ($mac === '' || strlen(str_replace(':', '', $mac)) !== 12) return null;
    $deviceType = da_normalize_device_type($deviceType);
    $reason = auth_pending_meta_value(['reason' => $reason], 'reason', 100);

    $st = $db->prepare('SELECT * FROM usuarios WHERE mac=? LIMIT 1');
    $st->execute([$mac]);
    $current = $st->fetch(PDO::FETCH_ASSOC) ?: null;
    $st->closeCursor();

    if (!$current) {
        $current = auth_ensure_pending_mac($db, $mac, $deviceType);
    }

    if ($current) {
        $hasCredentials = auth_user_has_credentials($current);
        $set = [];
        $params = [];

        if ($clearCredentials) {
            $set[] = "dns=''";
            $set[] = "username=''";
            $set[] = "password=''";
            $set[] = "status='aguardando'";
            $set[] = "vencimento=''";
        } elseif (!$hasCredentials) {
            // Se apenas um dos três campos foi removido, elimina os restantes
            // para não deixar uma credencial parcial reaproveitável no painel.
            $set[] = "dns=''";
            $set[] = "username=''";
            $set[] = "password=''";
            $set[] = "status='aguardando'";
            $set[] = "vencimento=''";
        }

        if (($clearCredentials || !$hasCredentials) && auth_column_exists($db, 'usuarios', 'login_mode')) {
            $set[] = "login_mode='mac'";
        }

        if (auth_column_exists($db, 'usuarios', 'device_type')) {
            $set[] = 'device_type=?';
            $params[] = $deviceType;
        }
        if (auth_column_exists($db, 'usuarios', 'last_device_type')) {
            $set[] = 'last_device_type=?';
            $params[] = $deviceType;
        }

        $nome = auth_pending_meta_value($meta, 'nome_cliente', 160);
        $whatsapp = auth_pending_meta_value($meta, 'whatsapp', 60);
        if ($nome !== '' && auth_column_exists($db, 'usuarios', 'nome_cliente')) {
            $set[] = "nome_cliente=CASE WHEN TRIM(COALESCE(nome_cliente,''))='' OR nome_cliente LIKE 'Cliente %' THEN ? ELSE nome_cliente END";
            $params[] = $nome;
        }
        if ($whatsapp !== '' && auth_column_exists($db, 'usuarios', 'whatsapp')) {
            $set[] = "whatsapp=CASE WHEN TRIM(COALESCE(whatsapp,''))='' THEN ? ELSE whatsapp END";
            $params[] = $whatsapp;
        }

        if ($set) {
            $params[] = $mac;
            $up = $db->prepare('UPDATE usuarios SET ' . implode(', ', $set) . ' WHERE mac=?');
            $up->execute($params);
        }
    }

    try {
        $metaParams = [
            $mac,
            $deviceType,
            auth_pending_meta_value($meta, 'device_name', 160),
            auth_pending_meta_value($meta, 'device_brand', 100),
            auth_pending_meta_value($meta, 'device_model', 140),
            auth_pending_meta_value($meta, 'android_version', 80),
            auth_pending_meta_value($meta, 'app_version', 80),
            auth_pending_meta_value($meta, 'android_id', 160),
            $reason,
        ];
        $sql = "INSERT INTO device_pending_info
            (mac,device_type,device_name,device_brand,device_model,android_version,app_version,android_id,pending_reason,created_at,updated_at)
            VALUES (?,?,?,?,?,?,?,?,?,strftime('%s','now'),strftime('%s','now'))
            ON CONFLICT(mac) DO UPDATE SET
                device_type=excluded.device_type,
                device_name=CASE WHEN excluded.device_name<>'' THEN excluded.device_name ELSE device_pending_info.device_name END,
                device_brand=CASE WHEN excluded.device_brand<>'' THEN excluded.device_brand ELSE device_pending_info.device_brand END,
                device_model=CASE WHEN excluded.device_model<>'' THEN excluded.device_model ELSE device_pending_info.device_model END,
                android_version=CASE WHEN excluded.android_version<>'' THEN excluded.android_version ELSE device_pending_info.android_version END,
                app_version=CASE WHEN excluded.app_version<>'' THEN excluded.app_version ELSE device_pending_info.app_version END,
                android_id=CASE WHEN excluded.android_id<>'' THEN excluded.android_id ELSE device_pending_info.android_id END,
                pending_reason=CASE WHEN excluded.pending_reason<>'' THEN excluded.pending_reason ELSE device_pending_info.pending_reason END,
                updated_at=strftime('%s','now')";
        $db->prepare($sql)->execute($metaParams);
    } catch (Throwable $e) {
    }

    $st = $db->prepare('SELECT * FROM usuarios WHERE mac=? LIMIT 1');
    $st->execute([$mac]);
    $saved = $st->fetch(PDO::FETCH_ASSOC) ?: null;
    $st->closeCursor();
    return $saved;
}

function auth_mark_device_active(PDO $db, string $mac): void {
    $mac = auth_normalize_mac($mac);
    if ($mac === '') return;
    try {
        auth_ensure_schema($db);
        $db->prepare("UPDATE device_pending_info SET pending_reason='', updated_at=strftime('%s','now') WHERE mac=?")->execute([$mac]);
    } catch (Throwable $e) {
    }
}

function auth_waiting_payload(string $message = 'Aguardando DNS, usuário e senha.'): array {
    return [
        'status' => 'waiting',
        'mac_registered' => true,
        'mac_pending' => true,
        'mac_has_credentials' => false,
        'logout' => false,
        'message' => $message,
    ];
}

function auth_refresh_user_after_validation(PDO $db, array $userRow, array $validation, string $deviceType = 'tv'): array {
    $mac = auth_normalize_mac((string)($userRow['mac'] ?? ''));
    $dns = auth_normalize_dns((string)($validation['dns'] ?? ($userRow['dns'] ?? '')));
    $exp = (int)($validation['exp'] ?? 0);
    $vencimento = $exp > 0 ? $exp : auth_parse_vencimento_to_timestamp($userRow['vencimento'] ?? 0);
    $deviceType = da_normalize_device_type($deviceType);
    try {
        $st = $db->prepare("UPDATE usuarios SET dns = ?, vencimento = ?, status = 'ativo', device_type = ?, last_device_type = ? WHERE mac = ?");
        $st->execute([$dns, $vencimento > 0 ? (string)$vencimento : '', $deviceType, $deviceType, $mac]);
    } catch (Throwable $e) {}
    $userRow['dns'] = $dns;
    $userRow['vencimento'] = $vencimento > 0 ? (string)$vencimento : '';
    $userRow['status'] = 'ativo';
    $userRow['device_type'] = $deviceType;
    $userRow['last_device_type'] = $deviceType;
    return $userRow;
}

function auth_public_base_url(): string {
    return media_public_base_url();
}

function auth_digits_only(string $value): string {
    return preg_replace('/\D+/', '', $value) ?: '';
}

function auth_branding_payload(PDO $db, array $userRow = []): array {
    $ownerId = max(0, (int)($userRow['usuario_id'] ?? 0));
    $ownerType = $ownerId > 0 ? 'revendedor' : 'admin';
    $logoRecord = branding_direct_record($db, $ownerType, $ownerId);
    $logoUrl = branding_logo_url($db, $ownerType, $ownerId);
    $logoVersion = (int)($logoRecord['updated_at'] ?? 0);
    $supportWhatsapp = '';
    $qrcodeUrl = '';
    $qrcodePayload = '';

    try {
        if ($ownerId > 0) {
            $st = $db->prepare('SELECT whatsapp FROM revendedores WHERE id = ? LIMIT 1');
            $st->execute([$ownerId]);
            $rev = $st->fetch(PDO::FETCH_ASSOC) ?: [];
            $supportWhatsapp = auth_digits_only((string)($rev['whatsapp'] ?? ''));
        }

        $cfg = $db->query("SELECT qrcode_whatsapp, qrcode_url FROM app_config WHERE id = 1 LIMIT 1")->fetch(PDO::FETCH_ASSOC) ?: [];
        if ($supportWhatsapp === '') $supportWhatsapp = auth_digits_only((string)($cfg['qrcode_whatsapp'] ?? ''));
        $qrcodeUrl = trim((string)($cfg['qrcode_url'] ?? ''));
        if ($supportWhatsapp !== '') {
            $qrcodePayload = 'https://wa.me/' . $supportWhatsapp;
        } elseif ($qrcodeUrl !== '') {
            $qrcodePayload = $qrcodeUrl;
        }
    } catch (Throwable $e) {}

    return [
        'owner_type' => $ownerType,
        'owner_id' => $ownerId,
        'revendedor_id' => $ownerId,
        'logo_url' => $logoUrl,
        'revenda_logo_url' => $logoUrl,
        'logo_version' => $logoVersion,
        'logo_updated_at' => $logoVersion,
        'logo_hash' => (string)($logoRecord['sha256'] ?? ''),
        'logo_width' => (int)($logoRecord['width'] ?? 0),
        'logo_height' => (int)($logoRecord['height'] ?? 0),
        'support_whatsapp' => $supportWhatsapp,
        'qrcode_url' => $qrcodeUrl,
        'qrcode_payload' => $qrcodePayload,
    ];
}

function auth_build_success_payload(PDO $db, array $userRow, array $dnsList, ?string $forcedDns = null, array $extra = []): array {
    auth_ensure_user_activation_code($db, $userRow);
    $username = trim((string)($userRow['username'] ?? ''));
    $password = trim((string)($userRow['password'] ?? ''));
    $dnsSaved = auth_normalize_dns((string)($forcedDns ?: ($userRow['dns'] ?? '')));
    if ($dnsSaved !== '' && !in_array($dnsSaved, $dnsList, true)) {
        array_unshift($dnsList, $dnsSaved);
    }
    $vencimentoRaw = $userRow['vencimento'] ?? '';
    $vencimento = '';
    $ts = auth_parse_vencimento_to_timestamp($vencimentoRaw);
    if ($ts > 0) {
        $vencimento = date('Y-m-d H:i:s', $ts);
    }
    $deviceType = da_normalize_device_type((string)($userRow['device_type'] ?? $userRow['last_device_type'] ?? 'tv'));
    $accessProfile = da_get_profile_by_key($db, da_user_key($username, $password));
    $dnsClean = array_values(array_unique(array_filter(array_map('auth_normalize_dns', $dnsList))));
    $branding = auth_branding_payload($db, $userRow);
    return array_merge([
        'status' => 'ok',
        'mac_registered' => true,
        'mac_pending' => false,
        'mac_has_credentials' => true,
        'logout' => false,
        'dns' => $dnsClean,
        'dns_list' => $dnsClean,
        'dns_selected' => $dnsSaved,
        'username' => $username,
        'password' => $password,
        'vencimento' => $vencimento,
        'nome_cliente' => trim((string)($userRow['nome_cliente'] ?? $userRow['nome'] ?? '')),
        'whatsapp' => trim((string)($userRow['whatsapp'] ?? '')),
        'login_mode' => trim((string)($userRow['login_mode'] ?? 'normal')),
        'activation_code' => trim((string)($userRow['activation_code'] ?? '')),
        'device_type' => $deviceType,
        'allow_tv' => $accessProfile['allow_tv'],
        'allow_mobile' => $accessProfile['allow_mobile'],
        'allow_movies' => $accessProfile['allow_movies'],
        'allow_series' => $accessProfile['allow_series'],
        'allow_live' => $accessProfile['allow_live'],
        'server_ts' => time(),
    ], $branding, $extra);
}
