<?php
// includes/auth-functions.php

/**
 * Funções de Autenticação e Gestão de Sessão do 1MZ For Artists.
 * Lida com login via Telemóvel + PIN, sessões PHP e criação de novas contas.
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Acesso direto bloqueado
}

/**
 * Inicia a sessão PHP em todas as páginas.
 * Essencial para o sistema "lembrar" do artista logado.
 */
function rmbz_init_session() {
    // Evitar warnings de headers já enviados
    if ( headers_sent() ) {
        return;
    }

    if ( ! session_id() ) {
        session_start();
    }
}
add_action('init', 'rmbz_init_session', 1);


/**
 * Verifica se o utilizador (artista) está atualmente logado no nosso sistema
 * e se a sua conta ainda existe na base de dados.
 *
 * @return bool True se estiver logado e existir, false caso contrário.
 */
function rmbz_is_user_logged_in() {
    // 1. Verifica se existe sessão no navegador
    if ( isset($_SESSION['rmbz_user_telemovel']) ) {
        $telemovel = $_SESSION['rmbz_user_telemovel'];

        // 2. SEGURANÇA EXTRA: Verifica se o utilizador ainda existe na Base de Dados
        global $wpdb;
        $table = $wpdb->prefix . 'rmbz_wallets';

        $row = $wpdb->get_row( $wpdb->prepare( "SELECT id, extra_data FROM {$table} WHERE user_telemovel = %s", $telemovel ) );

        // 3. Se a sessão existe mas o utilizador foi apagado da BD (Sessão Fantasma)
        if ( ! $row ) {
            unset($_SESSION['rmbz_user_telemovel']); // Força o logout imediato
            return false;
        }

        // 4. [1.5.455] SESSION EPOCH — o admin pode "terminar sessões ativas"
        // do artista: incrementa extra_data['session_epoch'] na wallet e
        // qualquer sessão de browser aberta ANTES desse momento morre aqui.
        // Sessões novas guardam o epoch atual no login e continuam válidas.
        $x = ! empty( $row->extra_data ) ? json_decode( (string) $row->extra_data, true ) : [];
        $wallet_epoch  = is_array( $x ) ? (int) ( $x['session_epoch'] ?? 0 ) : 0;
        $session_epoch = (int) ( $_SESSION['rmbz_session_epoch'] ?? 0 );
        if ( $wallet_epoch > $session_epoch ) {
            unset( $_SESSION['rmbz_user_telemovel'], $_SESSION['rmbz_session_epoch'] );
            return false;
        }

        return true;
    }

    // [1.5.197] BYPASS PARA WP ADMIN
    //
    // Se o utilizador está autenticado no WordPress como admin (manage_options),
    // permite acesso ao painel sem login por telefone. Quando admin chega ao
    // painel via "Editar como admin" ou directamente, pode actuar como qualquer
    // artista (o telemovel é resolvido a partir do release_id em contexto).
    //
    // Segurança:
    //   - Usa autenticação WP nativa (robusta, suporta 2FA)
    //   - Audit trail mantém WP user ID
    //   - Sem mudança permanente à sessão — só "simulação" durante o request
    if ( function_exists('current_user_can') && current_user_can('manage_options') ) {
        return true;
    }

    return false;
}


/**
 * Obtém o número de telemóvel do utilizador atualmente logado.
 *
 * @return string|null O número de telemóvel ou null se não estiver logado.
 */
function rmbz_get_current_user_telemovel() {
    // 1. Sessão normal de artista — prioridade
    if ( isset($_SESSION['rmbz_user_telemovel']) ) {
        // Verificação de existência (anti-sessão fantasma)
        global $wpdb;
        $table = $wpdb->prefix . 'rmbz_wallets';
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT id, extra_data FROM {$table} WHERE user_telemovel = %s",
            $_SESSION['rmbz_user_telemovel']
        ) );
        if ( $row ) {
            // [1.5.455] Mesma verificação de session_epoch do is_logged_in.
            $x = ! empty( $row->extra_data ) ? json_decode( (string) $row->extra_data, true ) : [];
            $wallet_epoch = is_array( $x ) ? (int) ( $x['session_epoch'] ?? 0 ) : 0;
            if ( $wallet_epoch > (int) ( $_SESSION['rmbz_session_epoch'] ?? 0 ) ) {
                unset( $_SESSION['rmbz_user_telemovel'], $_SESSION['rmbz_session_epoch'] );
            } else {
                return $_SESSION['rmbz_user_telemovel'];
            }
        } else {
            unset( $_SESSION['rmbz_user_telemovel'] );
        }
    }

    // [1.5.197] BYPASS PARA WP ADMIN
    //
    // Se o utilizador é WP admin sem sessão de telefone, resolve o telemovel
    // contextualmente:
    //   1. Se ?id=X (release_id) na URL → usar artist_telemovel desse release
    //   2. Se ?as=PHONE → admin escolheu um artista específico para "personificar"
    //      (futuro — não implementado ainda)
    //   3. Caso contrário → usar primeiro admin (ou null para forçar UI de
    //      escolha de artista — futuro)
    if ( function_exists('current_user_can') && current_user_can('manage_options') ) {
        // Resolução contextual via release_id
        if ( ! empty( $_GET['id'] ) && intval($_GET['id']) > 0 ) {
            global $wpdb;
            $artist_phone = $wpdb->get_var( $wpdb->prepare(
                "SELECT artist_telemovel FROM {$wpdb->prefix}rmbz_distro_releases WHERE id = %d",
                intval($_GET['id'])
            ) );
            if ( ! empty( $artist_phone ) ) {
                return $artist_phone;
            }
        }
        // Fallback: null — o painel mostra mensagem "escolhe artista"
        return null;
    }

    return null;
}


/**
 * Realiza o "login" do utilizador, guardando o seu telemóvel na sessão.
 *
 * @param string $telemovel O número de telemóvel a ser guardado na sessão.
 */
function rmbz_handle_login($telemovel) {
    // Regenera o ID da sessão para segurança (prevenção de session fixation)
    session_regenerate_id();
    $_SESSION['rmbz_user_telemovel'] = $telemovel;

    // [1.5.455] Guarda o session_epoch atual da conta — se o admin "terminar
    // sessões" mais tarde (epoch novo na wallet), esta sessão deixa de valer.
    global $wpdb;
    $x_raw = $wpdb->get_var( $wpdb->prepare(
        "SELECT extra_data FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s", $telemovel
    ) );
    $x = $x_raw ? json_decode( (string) $x_raw, true ) : [];
    $_SESSION['rmbz_session_epoch'] = is_array( $x ) ? (int) ( $x['session_epoch'] ?? 0 ) : 0;

    // Hook para outros módulos reagirem ao login (ex: distribution-splits.php
    // usa para libertar royalties retidos de colaboradores que agora se
    // registaram na 1MZ).
    do_action('rmbz_user_logged_in', $telemovel);
}


/**
 * Realiza o "logout" do utilizador, limpando a sessão.
 */
function rmbz_handle_logout() {
    unset($_SESSION['rmbz_user_telemovel']);
}


/**
 * Verifica se um PIN fornecido corresponde ao PIN guardado (hashed) na base de dados.
 *
 * @param string $telemovel O telemóvel do utilizador.
 * @param string $pin_fornecido O PIN de 4 dígitos (em texto simples) para verificar.
 * @return bool True se o PIN estiver correto, false caso contrário.
 */
function rmbz_verify_user_pin($telemovel, $pin_fornecido) {
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_wallets';

    // Busca o PIN criptografado (hashed) na base de dados.
    $hashed_pin = $wpdb->get_var($wpdb->prepare("SELECT user_pin FROM $table WHERE user_telemovel = %s", $telemovel));

    // Se não encontrarmos um utilizador com esse telemóvel, falha.
    if ( ! $hashed_pin ) {
        return false;
    }

    // [1.6.118.12] Auto-recovery de PINs em texto plano.
    // Bug histórico em admin-user-profile.php gravava PINs sem hash.
    // Se o "hash" guardado é literalmente um PIN de 4 dígitos numérico,
    // comparamos directamente e, se bater, re-hashamos para corrigir.
    // PINs hashed começam com `$wp$2y$...` ou `$P$...` — nunca são apenas dígitos.
    if ( strlen( $hashed_pin ) === 4 && ctype_digit( $hashed_pin ) ) {
        if ( $hashed_pin === $pin_fornecido ) {
            // PIN bate. Re-hash para corrigir a BD.
            $new_hash = wp_hash_password( $pin_fornecido );
            $wpdb->update(
                $table,
                [ 'user_pin' => $new_hash ],
                [ 'user_telemovel' => $telemovel ],
                [ '%s' ], [ '%s' ]
            );
            error_log( sprintf(
                '[1MZ pin_auto_recovery] PIN em texto plano detectado e re-hashed para %s.',
                $telemovel
            ) );
            return true;
        }
        return false;
    }

    // Usa a função segura do WordPress para comparar o texto simples com o hash.
    return wp_check_password($pin_fornecido, $hashed_pin);
}


/**
 * Cria uma nova conta de utilizador (carteira) na base de dados.
 *
 * @param string $telemovel O número de telemóvel do novo utilizador.
 * @param string $pin O PIN de 4 dígitos escolhido pelo utilizador.
 * @param string $email O email do novo utilizador.
 * @param string $nome O nome do novo utilizador.
 * @return bool True se a conta foi criada, false se já existia ou houve erro.
 */
function rmbz_create_user_account($telemovel, $pin, $email, $nome) {
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_wallets';

    // Verifica se já existe um utilizador com este número.
    $exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(id) FROM $table WHERE user_telemovel = %s", $telemovel));
    if ($exists > 0) {
        return false; // Conta já existe.
    }

    // SEGURANÇA: Criptografa o PIN antes de guardar.
    $hashed_pin = wp_hash_password($pin);

    $result = $wpdb->insert(
        $table,
        [
            'user_telemovel' => $telemovel,
            'user_pin'       => $hashed_pin,
            'user_email'     => $email,
            'user_nome'      => $nome,
            'balance'        => 0.00, // Saldo inicial
            'is_creator'     => 0     // Por defeito, não é admin/produtor
        ],
        [
            '%s',
            '%s',
            '%s',
            '%s',
            '%f',
            '%d'
        ]
    );

    return $result !== false;
}

/**
 * ==========================================================================
 * SISTEMA DE RECUPERAÇÃO DE PIN (PASSO 1: VERIFICAÇÃO E GERAÇÃO DA CHAVE)
 * ==========================================================================
 *
 * [SEC-AUTH1] Hardening 2026-04:
 *   - Garantir que a sessão está iniciada antes de escrever em $_SESSION
 *     (recovery é por definição usado por utilizadores não logados).
 *   - Rate limit por IP (5 tentativas/min) para mitigar enumeração de contas.
 *   - Mensagem de erro idêntica para "conta não existe" e "nome não bate"
 *     para não vazar quais telemóveis estão registados.
 *   - Chave de reset gerada com random_int (CSPRNG) em vez de mt_rand.
 */
function rmbz_verify_recovery_account() {
    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'rmbz_recovery_nonce' ) ) wp_die('Falha de segurança!');

    if ( session_status() === PHP_SESSION_NONE && ! headers_sent() ) { session_start(); }

    // Rate limit anti brute-force / enumeração.
    if ( function_exists('rmbz_rate_limit') ) {
        $ip = isset($_SERVER['REMOTE_ADDR']) ? (string) $_SERVER['REMOTE_ADDR'] : 'unknown';
        if ( ! rmbz_rate_limit( 'recovery_ip_' . md5($ip), 5 ) ) {
            $_SESSION['rmbz_login_error'] = 'Demasiadas tentativas. Aguarde 1 minuto e tente novamente.';
            $url_base = home_url('/minha-conta/');
            if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '1', $url_base) ); }
            else { wp_redirect( add_query_arg('recovery_step', '1', $url_base) ); exit; }
        }
    }

    global $wpdb;
    $nome = isset($_POST['rec_nome']) ? sanitize_text_field( wp_unslash($_POST['rec_nome']) ) : '';
    $telemovel_input = isset($_POST['rec_telemovel']) ? sanitize_text_field( wp_unslash($_POST['rec_telemovel']) ) : '';

    // Limpar o número para formato padrão
    $clean_input = preg_replace('/\s+/', '', $telemovel_input);
    $telemovel = (strpos($clean_input, '+258') === 0) ? $clean_input : '+258' . $clean_input;

    $table = $wpdb->prefix . 'rmbz_wallets';
    $user = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE user_telemovel = %s", $telemovel));

    $url_base = home_url('/minha-conta/');

    // 1. Verificar se a conta existe e se o NOME bate certo
    // [SEC-AUTH1] Mensagem genérica para evitar enumeração de contas.
    $user_nome_db = $user ? (string) $user->user_nome : '';
    if ( ! $user || strcasecmp(trim($user_nome_db), trim($nome)) !== 0 ) {
        $_SESSION['rmbz_login_error'] = 'Erro: Os dados inseridos não coincidem com nenhuma conta.';
        if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '1', $url_base) ); } 
        else { wp_redirect( add_query_arg('recovery_step', '1', $url_base) ); exit; }
    }

    $extra = !empty($user->extra_data) ? json_decode($user->extra_data, true) : [];
    if ( ! is_array($extra) ) $extra = [];

    // 2. Verificar a regra de bloqueio de 30 dias
    if ( !empty($extra['last_pin_reset']) ) {
        $dias_passados = floor((time() - strtotime($extra['last_pin_reset'])) / 86400);
        if ($dias_passados < 30) {
            $faltam = 30 - $dias_passados;
            $_SESSION['rmbz_login_error'] = "Acesso Negado: Por segurança, a troca de senha só é permitida 1 vez por mês. Tente novamente daqui a {$faltam} dias.";
            if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '1', $url_base) ); } 
            else { wp_redirect( add_query_arg('recovery_step', '1', $url_base) ); exit; }
        }
    }

    // 3. Gerar Chave de Segurança de 6 dígitos e gravar VALIDADE DE 15 MINUTOS
    // [SEC-AUTH1] random_int() usa CSPRNG; mt_rand() era previsível.
    try {
        $reset_key = sprintf("%06d", random_int(0, 999999));
    } catch (Exception $e) {
        // Fallback ultra-improvável (CSPRNG indisponível); ainda é melhor que mt_rand
        $reset_key = sprintf("%06d", hexdec( substr( bin2hex( random_bytes(4) ), 0, 5 ) ) % 1000000);
    }
    $extra['reset_key'] = $reset_key;
    $extra['reset_key_expires'] = time() + (15 * 60); // Hora atual + 15 minutos (em segundos)
    $extra['reset_key_attempts'] = 0; // [SEC-AUTH1] contador para limitar brute-force da chave de 6 dígitos

    $wpdb->update($table, ['extra_data' => wp_json_encode($extra)], ['user_telemovel' => $telemovel]);

    // Gravar sessão temporária para o passo 2
    $_SESSION['rmbz_recovery_phone'] = $telemovel;
    
    // Avançar para o Passo 2
    if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '2', $url_base) ); } 
    else { wp_redirect( add_query_arg('recovery_step', '2', $url_base) ); exit; }
}

add_action( 'admin_post_rmbz_verify_recovery', 'rmbz_verify_recovery_account' );
add_action( 'admin_post_nopriv_rmbz_verify_recovery', 'rmbz_verify_recovery_account' );


/**
 * ==========================================================================
 * SISTEMA DE RECUPERAÇÃO DE PIN (PASSO 2: EXECUÇÃO DO NOVO PIN)
 * ==========================================================================
 *
 * [SEC-AUTH2] Hardening 2026-04:
 *   - hash_equals() para comparação time-safe da chave (mitiga timing attack).
 *   - Limite de 5 tentativas por chave; à 6.ª tentativa a chave é destruída
 *     (mitiga brute-force das 1 000 000 hipóteses).
 *   - Validação básica do novo PIN (4-8 dígitos numéricos).
 *   - Garantir sessão antes de escrever em $_SESSION.
 */
function rmbz_execute_pin_reset() {
    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'rmbz_execute_reset_nonce' ) ) wp_die('Falha de segurança!');

    if ( session_status() === PHP_SESSION_NONE && ! headers_sent() ) { session_start(); }

    global $wpdb;
    $reset_key_input = isset($_POST['rec_key']) ? sanitize_text_field( wp_unslash($_POST['rec_key']) ) : '';
    $new_pin = isset($_POST['rec_new_pin']) ? sanitize_text_field( wp_unslash($_POST['rec_new_pin']) ) : '';
    $telemovel = isset($_SESSION['rmbz_recovery_phone']) ? $_SESSION['rmbz_recovery_phone'] : '';

    $url_base = home_url('/minha-conta/');

    if (empty($telemovel)) {
        $_SESSION['rmbz_login_error'] = 'Sessão de recuperação expirada. Tente começar novamente.';
        if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '1', $url_base) ); } 
        else { wp_redirect( add_query_arg('recovery_step', '1', $url_base) ); exit; }
    }

    // [SEC-AUTH2] Validar formato do novo PIN antes de qualquer escrita.
    if ( ! preg_match('/^\d{4,8}$/', $new_pin) ) {
        $_SESSION['rmbz_login_error'] = 'O PIN deve ter 4 a 8 dígitos numéricos.';
        if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '2', $url_base) ); }
        else { wp_redirect( add_query_arg('recovery_step', '2', $url_base) ); exit; }
    }

    $table = $wpdb->prefix . 'rmbz_wallets';
    $user = $wpdb->get_row($wpdb->prepare("SELECT extra_data FROM {$table} WHERE user_telemovel = %s", $telemovel));
    $extra = !empty($user->extra_data) ? json_decode($user->extra_data, true) : [];
    if ( ! is_array($extra) ) $extra = [];

    // [SEC-AUTH2] Limitar tentativas de adivinhar a chave de 6 dígitos.
    $attempts = isset($extra['reset_key_attempts']) ? (int) $extra['reset_key_attempts'] : 0;
    if ( $attempts >= 5 ) {
        unset($extra['reset_key'], $extra['reset_key_expires'], $extra['reset_key_attempts']);
        $wpdb->update($table, ['extra_data' => wp_json_encode($extra)], ['user_telemovel' => $telemovel]);
        unset($_SESSION['rmbz_recovery_phone']);
        $_SESSION['rmbz_login_error'] = 'Excedeu o número de tentativas. Inicie o pedido de recuperação novamente.';
        if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '1', $url_base) ); }
        else { wp_redirect( add_query_arg('recovery_step', '1', $url_base) ); exit; }
    }

    // 1. Verificar se a Chave bate certo (comparação time-safe).
    $stored_key = isset($extra['reset_key']) ? (string) $extra['reset_key'] : '';
    if ( $stored_key === '' || ! hash_equals($stored_key, (string) $reset_key_input) ) {
        $extra['reset_key_attempts'] = $attempts + 1;
        $wpdb->update($table, ['extra_data' => wp_json_encode($extra)], ['user_telemovel' => $telemovel]);

        $restantes = 5 - $extra['reset_key_attempts'];
        $_SESSION['rmbz_login_error'] = 'Erro: A Chave de Segurança inserida é inválida. Tentativas restantes: ' . max(0, $restantes);
        if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '2', $url_base) ); } 
        else { wp_redirect( add_query_arg('recovery_step', '2', $url_base) ); exit; }
    }

    // 2. VERIFICAR SE A CHAVE JÁ EXPIROU (Passaram os 15 minutos?)
    if ( empty($extra['reset_key_expires']) || time() > (int) $extra['reset_key_expires'] ) {
        unset($extra['reset_key'], $extra['reset_key_expires'], $extra['reset_key_attempts']);
        $wpdb->update($table, ['extra_data' => wp_json_encode($extra)], ['user_telemovel' => $telemovel]);
        
        $_SESSION['rmbz_login_error'] = 'Erro: A Chave de Segurança expirou (passaram mais de 15 minutos). Por favor, inicie o pedido novamente.';
        if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( add_query_arg('recovery_step', '1', $url_base) ); } 
        else { wp_redirect( add_query_arg('recovery_step', '1', $url_base) ); exit; }
    }

    // 3. Tudo certo! Mudar o PIN
    $hashed_pin = wp_hash_password($new_pin);
    $extra['last_pin_reset'] = current_time('mysql'); 
    unset($extra['reset_key'], $extra['reset_key_expires'], $extra['reset_key_attempts']);

    $wpdb->update($table, ['user_pin' => $hashed_pin, 'extra_data' => wp_json_encode($extra)], ['user_telemovel' => $telemovel]);

    // Limpar sessão
    unset($_SESSION['rmbz_recovery_phone']);
    
    // Sucesso e Redirecionar
    $_SESSION['rmbz_withdrawal_notice'] = ['success', 'O seu PIN foi alterado com sucesso! Já pode fazer o login na sua conta. Atenção: Só poderá alterar a sua senha novamente daqui a 30 dias.'];
    if (function_exists('rmbz_safe_redirect')) { rmbz_safe_redirect( $url_base ); } 
    else { wp_redirect( $url_base ); exit; }
}

add_action( 'admin_post_rmbz_execute_reset', 'rmbz_execute_pin_reset' );
add_action( 'admin_post_nopriv_rmbz_execute_reset', 'rmbz_execute_pin_reset' );

/**
 * [1.6.118.10] Lista de nomes reservados/proibidos para registo.
 *
 * Estes nomes são bloqueados no registo (app + site) para evitar:
 *   - Confusão com placeholders históricos ("Artista" era usado por
 *     distribution-financial.php quando criava wallets automáticas)
 *   - Contas de teste a poluir o sistema ("Teste", "Test")
 *   - Tentativas de impersonação (Admin)
 *
 * Comparação é case-insensitive e aplicada ao nome inteiro (não a uma
 * parte) — "João Artista" passa, "Artista" sozinho não.
 *
 * @return array Lista de nomes reservados (lowercase para comparação)
 */
function rmbz_get_reserved_artist_names() {
    return [
        'artista',
        'artist',
        'user',
        'usuario',
        'utilizador',
        'teste',
        'test',
        'testing',
        'admin',
        'administrador',
        'administrator',
        'anonimo',
        'anônimo',
        'anonymous',
        'unknown',
        'desconhecido',
        '1mz',
        '1mzrecords',
        'onemz',
        'onemzrecords',
        'null',
        'undefined',
        'none',
    ];
}


/**
 * [1.6.118.10] Valida se um nome é aceitável para registo.
 *
 * Regras:
 *   - Não vazio (>= 2 caracteres)
 *   - Não está na lista de nomes reservados
 *   - Tem pelo menos uma letra (rejeita "123", "...", "---")
 *
 * @param string $nome
 * @return string|true   true se válido, ou mensagem de erro
 */
function rmbz_validate_artist_name( $nome ) {
    $nome = trim( (string) $nome );

    if ( strlen( $nome ) < 2 ) {
        return 'Nome deve ter pelo menos 2 caracteres.';
    }

    // Tem pelo menos uma letra? (rejeita "123", "...", etc)
    if ( ! preg_match( '/\p{L}/u', $nome ) ) {
        return 'Nome inválido — deve conter letras.';
    }

    // Está na lista de reservados?
    $reserved = rmbz_get_reserved_artist_names();
    $lower = mb_strtolower( $nome, 'UTF-8' );
    if ( in_array( $lower, $reserved, true ) ) {
        return 'Este nome é reservado. Por favor escolhe outro nome real.';
    }

    return true;
}


/**
 * [1.6.118.9] Normaliza um nome de artista para capitalização correcta:
 *
 *   "joão pedro silva"    → "João Pedro Silva"
 *   "MARIA DA CONCEIÇÃO"  → "Maria Da Conceição"
 *   "anA caRoLina"        → "Ana Carolina"
 *
 * - Title case usando mb_convert_case (UTF-8 seguro)
 * - Preserva acentos
 * - Remove espaços extra
 *
 * Não aplica regras avançadas (não força "de/da/dos/do" em minúsculas)
 * — manter simples e previsível.
 *
 * Usado no registo (form-handler do site + auth-controller do app)
 * e no profile update.
 *
 * @param string $nome
 * @return string
 */
function rmbz_normalize_artist_name( $nome ) {
    $nome = trim( (string) $nome );
    if ( $nome === '' ) return '';

    // Colapsar espaços múltiplos
    $nome = preg_replace( '/\s+/', ' ', $nome );

    // Title case Unicode-aware
    if ( function_exists( 'mb_convert_case' ) ) {
        $nome = mb_convert_case( $nome, MB_CASE_TITLE, 'UTF-8' );
    } else {
        // Fallback se mbstring não disponível (raro)
        $nome = ucwords( strtolower( $nome ) );
    }

    return $nome;
}
