<?php
// includes/form-handler.php

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

/**
 * ==========================================================================
 * FUNÇÃO AUXILIAR: UPLOAD SEGURO (Compatível com Nuvem/S3)
 * ==========================================================================
 */
function rmbz_handle_proof_upload($file_input_name) {
    if ( !isset($_FILES[$file_input_name]) || empty($_FILES[$file_input_name]['name']) ) {
        return false;
    }

    if ( ! function_exists( 'wp_handle_upload' ) ) {
        require_once( ABSPATH . 'wp-admin/includes/file.php' );
    }
    
    $file = $_FILES[$file_input_name];

    // [SEC-FH6] Validar erros do PHP no upload primeiro.
    if ( ! empty($file['error']) && $file['error'] !== UPLOAD_ERR_OK ) return false;
    if ( ! is_uploaded_file($file['tmp_name']) ) return false;

    // Validação de Tamanho (10MB)
    $max_size = 10 * 1024 * 1024;
    if ( isset($file['size']) && (int) $file['size'] > $max_size ) {
        return false;
    }

    // Tipos Permitidos
    $allowed_mimes = [
        'jpg|jpeg' => 'image/jpeg',
        'png'      => 'image/png',
        'pdf'      => 'application/pdf',
        'mp3'      => 'audio/mpeg',
        'wav'      => 'audio/wav',
    ];

    if ( ! function_exists('wp_check_filetype_and_ext') ) {
        require_once( ABSPATH . 'wp-admin/includes/file.php' );
    }

    $checked = wp_check_filetype_and_ext($file['tmp_name'], $file['name'], $allowed_mimes);
    if ( empty($checked['ext']) || empty($checked['type']) ) {
        return false;
    }

    // [SEC-FH6] MIME real via finfo (defesa adicional).
    if ( function_exists('finfo_open') ) {
        $finfo = finfo_open( FILEINFO_MIME_TYPE );
        $real_mime = finfo_file( $finfo, $file['tmp_name'] );
        finfo_close( $finfo );
        $accepted_real = array_values($allowed_mimes);
        // PDF tem MIME variável conforme produtor; aceitar tb application/x-pdf.
        $accepted_real[] = 'application/x-pdf';
        $accepted_real[] = 'audio/x-wav';
        if ( $real_mime && ! in_array( $real_mime, $accepted_real, true ) ) {
            return false;
        }
    }

    // [SEC-FH6] Renomear o ficheiro para evitar nomes maliciosos / colisões.
    $ext = strtolower( pathinfo($file['name'], PATHINFO_EXTENSION) );
    $file['name'] = 'proof_' . wp_generate_password(20, false, false) . '.' . $ext;

    $upload_overrides = ['test_form' => false, 'mimes' => $allowed_mimes];
    $movefile = wp_handle_upload( $file, $upload_overrides );
    
    if ( $movefile && ! isset( $movefile['error'] ) ) {
        // Regista na Biblioteca de Media (Para integração com Leopard S3)
        $wp_filetype = wp_check_filetype(basename($movefile['file']), null);
        $attachment = [
            'post_mime_type' => $wp_filetype['type'],
            'post_title'     => preg_replace('/\.[^.]+$/', '', basename($movefile['file'])),
            'post_content'   => '',
            'post_status'    => 'inherit'
        ];
        
        $attach_id = wp_insert_attachment($attachment, $movefile['file']);
        
        if (!is_wp_error($attach_id)) {
            require_once(ABSPATH . 'wp-admin/includes/image.php');
            $attach_data = wp_generate_attachment_metadata($attach_id, $movefile['file']);
            wp_update_attachment_metadata($attach_id, $attach_data);
            return wp_get_attachment_url($attach_id); // Devolve o link seguro
        }
        return $movefile['url'];
    }
    return false;
}

/**
 * ==========================================================================
 * 7. PROCESSAMENTO DE RESGATE DE CUPÃO PELO ARTISTA (NO PAINEL)
 * ==========================================================================
 */
function rmbz_process_apply_coupon() {
    $redirect_url = wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/');

    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'rmbz_apply_coupon_nonce' ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Falha de segurança. Tente novamente.'];
        wp_redirect( $redirect_url ); exit;
    }
    
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Não autorizado.');

    $user_telemovel = rmbz_get_current_user_telemovel();
    $coupon_code = strtoupper(sanitize_text_field(str_replace(' ', '', $_POST['coupon_code'])));

    global $wpdb;
    $table_coupons = $wpdb->prefix . 'rmbz_coupons';
    $table_usage   = $wpdb->prefix . 'rmbz_coupon_usage';

    $coupon = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table_coupons} WHERE coupon_code = %s", $coupon_code));
    if (!$coupon) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Cupão inválido.']; wp_redirect( $redirect_url ); exit; }
    if ($coupon->status !== 'ativo') { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Cupão inativo.']; wp_redirect( $redirect_url ); exit; }
    if (!empty($coupon->expiry_date) && strtotime($coupon->expiry_date . ' UTC') < time()) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Cupão expirado.']; wp_redirect( $redirect_url ); exit; }
    if ($coupon->usage_limit > 0 && $coupon->used_count >= $coupon->usage_limit) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Cupão esgotado.']; wp_redirect( $redirect_url ); exit; }

    $already_used = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table_usage} WHERE coupon_id = %d AND user_telemovel = %s", $coupon->id, $user_telemovel));
    if ($already_used > 0) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Já utilizou este cupão!']; wp_redirect( $redirect_url ); exit; }

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

    if ($coupon->reward_type === 'saldo') {
        $details = "Resgate de Cupão: " . $coupon->coupon_code;
        $is_withdrawable = isset($extra['is_withdrawable']) ? (int)$extra['is_withdrawable'] : 0;
        
        $is_unlocked = ($is_withdrawable === 1) ? 1 : 0;
        $unlock_date = ($is_withdrawable === 1) ? null : '2099-12-31 23:59:59';

        $credit_result = rmbz_update_wallet_balance( $user_telemovel, (float)$coupon->reward_value, 'coupon_bonus', null, $details, $is_unlocked, $unlock_date );
        if (!$credit_result['success']) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro técnico.']; wp_redirect( $redirect_url ); exit; }
        
        $msg = 'Parabéns! ' . number_format((float)$coupon->reward_value, 2, ',', '.') . ' MT na carteira!';

    } elseif ($coupon->reward_type === 'vip_days') {
        $table_subs = $wpdb->prefix . 'rmbz_subscriptions';
        
        $sub = $wpdb->get_row($wpdb->prepare("SELECT id, end_date FROM {$table_subs} WHERE user_telemovel = %s ORDER BY end_date DESC LIMIT 1", $user_telemovel));
        
        $days = intval($coupon->reward_value);
        $now = current_time('mysql');
        $now_timestamp = current_time('timestamp');

        if ($sub && $sub->end_date > $now) {
            $new_end_date = date('Y-m-d H:i:s', strtotime("+$days days", strtotime($sub->end_date)));
            $wpdb->update($table_subs, ['end_date' => $new_end_date, 'status' => 'active'], ['id' => $sub->id], ['%s', '%s'], ['%d']);
        } else {
            $end_date = date('Y-m-d H:i:s', strtotime("+$days days", $now_timestamp));
            $wpdb->insert($table_subs, [
                'user_telemovel' => $user_telemovel,
                'start_date'     => $now,
                'end_date'       => $end_date,
                'status'         => 'active'
            ], ['%s', '%s', '%s', '%s']);
        }

        $wallet_table = $wpdb->prefix . 'rmbz_wallets';
        $wallet = $wpdb->get_row($wpdb->prepare("SELECT extra_data FROM {$wallet_table} WHERE user_telemovel = %s", $user_telemovel));
        $w_extra = !empty($wallet->extra_data) ? json_decode($wallet->extra_data, true) : [];
        if (isset($extra['vip_permissions'])) {
            $w_extra['vip_permissions'] = $extra['vip_permissions'];
            $wpdb->update($wallet_table, ['extra_data' => wp_json_encode($w_extra)], ['user_telemovel' => $user_telemovel]);
        }

        $msg = 'Parabéns! Ganhou ' . $days . ' dias VIP!';
    }

    $wpdb->insert($table_usage, ['coupon_id' => $coupon->id, 'user_telemovel' => $user_telemovel]);
    $wpdb->query($wpdb->prepare("UPDATE {$table_coupons} SET used_count = used_count + 1 WHERE id = %d", $coupon->id));

    // [1.5.298] Em vez da notice simples, guardar dados para o MODAL de
    // celebração que abre na página (parabéns + benefícios + IA).
    $is_vip = ($coupon->reward_type === 'vip_days');
    $perms  = ($is_vip && isset($extra['vip_permissions']) && is_array($extra['vip_permissions'])) ? $extra['vip_permissions'] : [];
    $has_ai = ! empty($perms['ai']);
    $benefits = [];
    if ($is_vip) {
        $benefits[] = ['icon'=>'💎','text'=> intval($coupon->reward_value) . ' dias de subscrição VIP'];
        if (!empty($perms['distribute'])) $benefits[] = ['icon'=>'🌍','text'=>'Distribuição nas lojas digitais'];
        if (!empty($perms['site']))       $benefits[] = ['icon'=>'📡','text'=>'Publicação no site'];
        if (!empty($perms['social']))     $benefits[] = ['icon'=>'📱','text'=>'Promoção nas redes sociais'];
        if (!empty($perms['video']))      $benefits[] = ['icon'=>'🎬','text'=>'Candidatura a videoclipe'];
        if ($has_ai)                      $benefits[] = ['icon'=>'🤖','text'=>'Assistente de IA desbloqueado!'];
    } else {
        $benefits[] = ['icon'=>'💰','text'=> number_format((float)$coupon->reward_value, 2, ',', '.') . ' MT na carteira'];
        if (!empty($extra['is_withdrawable'])) $benefits[] = ['icon'=>'🏦','text'=>'Podes levantar este saldo'];
    }
    $_SESSION['rmbz_coupon_celebrate'] = [
        'title'    => $is_vip ? 'Parabéns — és VIP!' : 'Parabéns!',
        'message'  => $msg,
        'is_vip'   => $is_vip,
        'has_ai'   => $has_ai,
        'benefits' => $benefits,
    ];
    wp_redirect( $redirect_url ); exit;
}
add_action('admin_post_rmbz_apply_coupon', 'rmbz_process_apply_coupon');
add_action('admin_post_nopriv_rmbz_apply_coupon', 'rmbz_process_apply_coupon');

/**
 * ==========================================================================
 * 1. PROCESSAR REGISTO DE NOVO ARTISTA (COM SUPORTE A CUPÃO VIP E POPUPS)
 * ==========================================================================
 */
function onemz_process_registration() {
    if (!session_id()) session_start();
    $redirect_url = home_url('/minha-conta/');
    
    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'onemz_registration_nonce' ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Falha de segurança. Por favor, atualize a página e tente novamente.'];
        wp_redirect( $redirect_url ); exit;
    }

    // VERIFICAÇÃO ANTI-BOT
    $bot_ans = isset($_POST['anti_bot_answer']) ? intval($_POST['anti_bot_answer']) : 0;
    $bot_hash = isset($_POST['anti_bot_hash']) ? $_POST['anti_bot_hash'] : '';
    if (md5($bot_ans . '1mz_bot_secret') !== $bot_hash) { 
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro Anti-Spam: A resposta da conta matemática está incorreta. Tente novamente.'];
        wp_redirect( $redirect_url ); exit;
    }

    $nome = isset($_POST['reg_nome']) ? sanitize_text_field($_POST['reg_nome']) : '';
    // [1.6.118.9] Normalizar capitalização — "joão silva" → "João Silva"
    if ( function_exists( 'rmbz_normalize_artist_name' ) ) {
        $nome = rmbz_normalize_artist_name( $nome );
    }

    // [1.6.118.10] Validar contra lista de nomes reservados
    // ("Artista", "Teste", "Admin", etc).
    if ( function_exists( 'rmbz_validate_artist_name' ) ) {
        $nome_valid = rmbz_validate_artist_name( $nome );
        if ( $nome_valid !== true ) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', $nome_valid];
            wp_redirect( $redirect_url ); exit;
        }
    }

    $telemovel_raw = isset($_POST['reg_telemovel']) ? sanitize_text_field($_POST['reg_telemovel']) : '';
    $pin = isset($_POST['reg_pin']) ? sanitize_text_field($_POST['reg_pin']) : '';
    
    $activation_type = isset($_POST['reg_activation_type']) ? sanitize_text_field($_POST['reg_activation_type']) : 'payment';

    // Remove TUDO o que não for número
    $apenas_numeros = preg_replace('/[^0-9]/', '', $telemovel_raw);

    if (empty($apenas_numeros)) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro: O número de telemóvel é inválido. Use apenas números.'];
        wp_redirect( $redirect_url ); exit;
    }

    if (strpos($apenas_numeros, '258') === 0) {
        $telemovel = '+' . $apenas_numeros;
    } else {
        $telemovel = '+258' . $apenas_numeros;
    }

    if (strlen($telemovel) !== 13) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro: O número de telemóvel inserido tem um tamanho inválido. Certifique-se que tem 9 dígitos (ex: 841234567).'];
        wp_redirect( $redirect_url ); exit;
    }
    
    if ( strlen($pin) !== 4 || !is_numeric($pin) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'O PIN deve ter exatamente 4 dígitos numéricos.'];
        wp_redirect( $redirect_url ); exit;
    }

    global $wpdb;
    $table_wallets = $wpdb->prefix . 'rmbz_wallets';
    
    $exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$table_wallets} WHERE user_telemovel = %s", $telemovel));
    if ($exists) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Este número já está registado. Por favor, clique no separador "Entrar".'];
        wp_redirect( $redirect_url ); exit;
    }

    // ========================================================================
    // VALIDAÇÃO PRÉ-CRIAÇÃO DE CONTA (CUPÃO OU PAGAMENTO)
    // ========================================================================
    $coupon = null;
    $metodo = '';
    $sender_phone = '';
    $transaction_id = '';
    $proof_image = '';

    if ($activation_type === 'coupon') {
        $coupon_code = isset($_POST['reg_coupon_code']) ? strtoupper(sanitize_text_field(str_replace(' ', '', $_POST['reg_coupon_code']))) : '';
        if (empty($coupon_code)) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Por favor, insira o código do cupão que deseja usar.'];
            wp_redirect( $redirect_url ); exit;
        }

        $table_coupons = $wpdb->prefix . 'rmbz_coupons';
        $coupon = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table_coupons} WHERE coupon_code = %s", $coupon_code));
        
        if (!$coupon) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'O Cupão inserido é inválido ou não existe.']; wp_redirect( $redirect_url ); exit; }
        if ($coupon->status !== 'ativo') { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Este cupão encontra-se inativo.']; wp_redirect( $redirect_url ); exit; }
        if (!empty($coupon->expiry_date) && strtotime($coupon->expiry_date . ' UTC') < time()) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Este cupão já expirou.']; wp_redirect( $redirect_url ); exit; }
        if ($coupon->usage_limit > 0 && $coupon->used_count >= $coupon->usage_limit) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'O limite de usos deste cupão já foi atingido.']; wp_redirect( $redirect_url ); exit; }
        
        if ($coupon->reward_type !== 'vip_days') {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro: Apenas cupões que oferecem "Dias VIP" são válidos para criar conta. Cupões de saldo não são aceites aqui.'];
            wp_redirect( $redirect_url ); exit;
        }

    } else {
        $metodo = isset($_POST['reg_payment_method']) ? sanitize_text_field($_POST['reg_payment_method']) : '';
        $sender_phone = isset($_POST['reg_sender_phone']) ? sanitize_text_field($_POST['reg_sender_phone']) : '';
        $proof_type = isset($_POST['reg_proof_type']) ? sanitize_text_field($_POST['reg_proof_type']) : '';
        
        if ( $proof_type === 'id' ) {
            $transaction_id = isset($_POST['reg_transaction_id']) ? sanitize_text_field($_POST['reg_transaction_id']) : '';
            if ( empty($transaction_id) ) {
                $_SESSION['rmbz_withdrawal_notice'] = ['error', 'O ID da transação é obrigatório para confirmar o pagamento.'];
                wp_redirect( $redirect_url ); exit;
            }
        } else {
            if ( !empty($_FILES['reg_proof_image']['name']) ) {
                $url = rmbz_handle_proof_upload('reg_proof_image');
                if ( $url ) {
                    $proof_image = $url;
                } else {
                    $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro ao fazer upload da imagem do comprovativo. Tente novamente.'];
                    wp_redirect( $redirect_url ); exit;
                }
            } else {
                $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Por favor, selecione a imagem do comprovativo de pagamento.'];
                wp_redirect( $redirect_url ); exit;
            }
        }
    }

    // ========================================================================
    // CRIAÇÃO DA CONTA
    // ========================================================================
    $email = 'artista_' . substr(md5($telemovel), 0, 8) . '@1mz.local';
    
    if ( function_exists('rmbz_create_user_account') ) {
        $conta_criada = rmbz_create_user_account($telemovel, $pin, $email, $nome);
    } else {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro interno de sistema ao comunicar com a base de dados.'];
        wp_redirect( $redirect_url ); exit;
    }
    
    // Guardar Província e Cidade nos dados extra do artista
    if ( $conta_criada ) {
        $provincia = isset($_POST['reg_provincia']) ? sanitize_text_field($_POST['reg_provincia']) : '';
        $cidade = isset($_POST['reg_cidade']) ? sanitize_text_field($_POST['reg_cidade']) : '';
        
        $wallet = $wpdb->get_row($wpdb->prepare("SELECT extra_data FROM {$table_wallets} WHERE user_telemovel = %s", $telemovel));
        $extra_data = !empty($wallet->extra_data) ? json_decode($wallet->extra_data, true) : [];
        
        $extra_data['provincia'] = $provincia;
        $extra_data['cidade'] = $cidade;
        
        $wpdb->update($table_wallets, ['extra_data' => wp_json_encode($extra_data)], ['user_telemovel' => $telemovel]);

        /* [1.5.131] Sistema de Convites: se o utilizador inseriu um número de
           convite no registo, gravamos `referred_by` na wallet E criamos uma
           entrada pending em rmbz_referral_log. A comissão só será paga
           quando o convidado cumprir 2 condições: 1º depósito aprovado +
           compra de plano VIP. Lógica em includes/referral-system.php.
           [1.5.133] Validação delegada a rmbz_referral_create_pending() que
           já trata: existência do convidador, auto-referral, blacklist,
           duplicados. Se devolver false (qualquer das validações falhou),
           NÃO grava referred_by — o registo continua normalmente sem
           ter referrer. */
        $reg_referral_raw = isset($_POST['reg_referral_phone']) ? sanitize_text_field( wp_unslash($_POST['reg_referral_phone']) ) : '';
        if ( ! empty($reg_referral_raw) && function_exists('rmbz_referral_create_pending') ) {
            // Normalizar formato: remove espaços, garante prefixo +258
            $clean = preg_replace('/\s+/', '', $reg_referral_raw);
            if ( strpos($clean, '+258') !== 0 ) {
                $clean = '+258' . ltrim($clean, '+');
            }
            // Tenta criar entry — devolve true se passou todas as validações
            $ok = rmbz_referral_create_pending( $telemovel, $clean );
            if ( $ok ) {
                $wpdb->update(
                    $table_wallets,
                    [ 'referred_by' => $clean ],
                    [ 'user_telemovel' => $telemovel ],
                    ['%s'], ['%s']
                );
            }
            // Se $ok === false, continuamos o registo sem referrer (silencioso)
        }
    }
    
    if ( ! $conta_criada ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro técnico: Falha ao gravar os dados de utilizador.'];
        wp_redirect( $redirect_url ); exit;
    }

    if ( function_exists('rmbz_handle_login') ) {
        rmbz_handle_login($telemovel);
    }

    // ========================================================================
    // ATIVAÇÃO PÓS-CRIAÇÃO
    // ========================================================================
    if ($activation_type === 'coupon' && $coupon) {
        
        $table_subs = $wpdb->prefix . 'rmbz_subscriptions';
        $days = intval($coupon->reward_value);
        $now = current_time('mysql');
        $now_timestamp = current_time('timestamp');
        $end_date = date('Y-m-d H:i:s', strtotime("+$days days", $now_timestamp));
        
        $wpdb->insert($table_subs, [
            'user_telemovel' => $telemovel,
            'start_date'     => $now,
            'end_date'       => $end_date,
            'status'         => 'active'
        ], ['%s', '%s', '%s', '%s']);
        
        $extra = !empty($coupon->extra_data) ? json_decode($coupon->extra_data, true) : [];
        if (isset($extra['vip_permissions'])) {
            $wallet = $wpdb->get_row($wpdb->prepare("SELECT extra_data FROM {$table_wallets} WHERE user_telemovel = %s", $telemovel));
            $w_extra = !empty($wallet->extra_data) ? json_decode($wallet->extra_data, true) : [];
            $w_extra['vip_permissions'] = $extra['vip_permissions'];
            $wpdb->update($table_wallets, ['extra_data' => wp_json_encode($w_extra)], ['user_telemovel' => $telemovel]);
        }
        
        $table_usage = $wpdb->prefix . 'rmbz_coupon_usage';
        $wpdb->insert($table_usage, ['coupon_id' => $coupon->id, 'user_telemovel' => $telemovel]);
        $wpdb->query($wpdb->prepare("UPDATE {$wpdb->prefix}rmbz_coupons SET used_count = used_count + 1 WHERE id = %d", $coupon->id));

        $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Bem-vindo! A sua conta foi criada e ativada instantaneamente com ' . $days . ' dias de Acesso VIP!'];
        wp_redirect($redirect_url);
        exit;

    } else {
        // [1.5.129] Valor do primeiro depósito vem da nova setting
        // `rmbz_first_deposit_min`. Se não estiver definida (instalações
        // antigas a fazer upgrade), cai no `rmbz_sub_price` legacy de
        // forma segura. Admin gere isto em Settings → 1MZ → "Inscrição
        // Inicial e Contactos de Suporte".
        $first_deposit = (float) get_option('rmbz_first_deposit_min', 0);
        if ( $first_deposit <= 0 ) {
            $first_deposit = (float) get_option('rmbz_sub_price', 1500);
        }
        $sub_price = $first_deposit;
        $table_deposits = $wpdb->prefix . 'rmbz_deposit_requests';

        $deposito_criado = $wpdb->insert(
            $table_deposits,
            [
                'user_telemovel'   => $telemovel,
                'amount'           => $sub_price,
                'status'           => 'pendente',
                'payment_method'   => $metodo,
                'transaction_id'   => $transaction_id,
                'proof_image'      => $proof_image,
                'sender_phone'     => $sender_phone,
                'request_date'     => current_time('mysql', 1),
                // [1.6.118] Marcar origem (site) e se é o primeiro depósito
                // do user — usado para badge "Abertura de conta" no admin
                // e para CRON auto-delete em 24h.
                'source_platform'  => 'site',
                'is_first_deposit' => function_exists('rmbz_is_first_deposit_for_user')
                    && rmbz_is_first_deposit_for_user( $telemovel ) ? 1 : 0,
            ],
            ['%s', '%f', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d']
        );

        if ($deposito_criado) {
            $novo_deposito_id = $wpdb->insert_id;
            if (empty($novo_deposito_id)) {
                $novo_deposito_id = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$table_deposits} WHERE user_telemovel = %s ORDER BY id DESC LIMIT 1", $telemovel));
            }

            // [1.5.396] Push aos admins (app 1MZ Admin).
            do_action( 'rmbz_deposit_request_created', (int) $novo_deposito_id, $telemovel, (float) $sub_price, 'site' );

            // [1.6.118] Marcar user como sujeito a regra "24h ou apaga".
            // Só users registados depois desta release ficam sujeitos.
            $new_user_obj = get_user_by( 'login', $telemovel );
            if ( $new_user_obj ) {
                update_user_meta( $new_user_obj->ID, 'rmbz_first_deposit_required', 1 );
                update_user_meta( $new_user_obj->ID, 'rmbz_first_deposit_at', current_time( 'mysql', 1 ) );
            }
            
            if ( function_exists('rmbz_send_admin_deposit_alert') ) {
                $tx_display = !empty($transaction_id) ? $transaction_id : 'Imagem/Screenshot (Ver no Painel)';
                rmbz_send_admin_deposit_alert($nome, $sub_price, $metodo, $tx_display, $novo_deposito_id);
            }

            // [1.5.138] Notificação ao próprio utilizador via Centro de Notificações.
            // Email + sino. Template editável em Settings → E-mails 📧.
            if ( function_exists('rmbz_notify') ) {
                rmbz_notify( $telemovel, 'welcome_pending', [
                    'nome_artista' => $nome,
                    'valor'        => number_format($sub_price, 0, ',', '.'),
                    'metodo'       => $metodo,
                ]);
            }

            $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Conta criada com sucesso! O pagamento inicial está em análise pela nossa equipa.'];
            wp_redirect($redirect_url);
            exit;
        } else {
            $wpdb->delete($table_wallets, ['user_telemovel' => $telemovel], ['%s']);
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro ao registar o seu pagamento na base de dados. A conta não foi criada. Tente novamente.'];
            wp_redirect($redirect_url);
            exit;
        }
    }
}
add_action('admin_post_onemz_process_registration', 'onemz_process_registration');
add_action('admin_post_nopriv_onemz_process_registration', 'onemz_process_registration');

/**
 * ==========================================================================
 * 2. PROCESSAR ENVIOS DO FORMULÁRIO PRINCIPAL E VALIDAÇÃO DE LINKS
 * ==========================================================================
 */

function rmbz_validar_link_plataforma($url, $plataforma) {
    if (empty($url)) return true;
    $url = strtolower($url);
    if ($plataforma === 'youtube') return (strpos($url, 'youtube.com') !== false || strpos($url, 'youtu.be') !== false);
    if ($plataforma === 'spotify') return (strpos($url, 'spotify.com') !== false);
    if ($plataforma === 'apple') return (strpos($url, 'apple.com') !== false || strpos($url, 'music.apple.com') !== false);
    if ($plataforma === 'drive') return (strpos($url, 'drive.google.com') !== false || strpos($url, 'dropbox.com') !== false || strpos($url, 'wetransfer.com') !== false || strpos($url, '1drv.ms') !== false || strpos($url, 'mega.nz') !== false);
    return true;
}

function rmbz_handle_frontend_upload() {
    $redirect_url = wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/'); 

    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Sessão expirada. Faça login novamente.'];
        wp_redirect( $redirect_url ); exit;
    }
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'rmbz_frontend_upload_nonce') ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Link de segurança inválido.'];
        wp_redirect( $redirect_url ); exit;
    }

    $telemovel = rmbz_get_current_user_telemovel();

    if ( ! function_exists('rmbz_user_has_active_subscription') || ! rmbz_user_has_active_subscription($telemovel) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'A sua subscrição VIP não está ativa.'];
        wp_redirect( $redirect_url ); exit;
    }

    global $wpdb;
    $table_submissions = $wpdb->prefix . 'rmbz_artist_submissions';
    $table_projects    = $wpdb->prefix . 'rmbz_artist_projects';

    $tem_musica_pendente = $wpdb->get_var( $wpdb->prepare("SELECT id FROM {$table_submissions} WHERE artist_telemovel = %s AND review_status = 'pendente'", $telemovel) );
    $tem_projeto_pendente = $wpdb->get_var( $wpdb->prepare("SELECT id FROM {$table_projects} WHERE artist_telemovel = %s AND production_status = 'pending_review'", $telemovel) );

    if ( $tem_musica_pendente || $tem_projeto_pendente ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Acesso Negado: Já tem um envio em análise! Aguarde a avaliação antes de enviar outro.'];
        wp_redirect( $redirect_url ); exit;
    }

    $submission_type = isset($_POST['submission_type']) ? sanitize_text_field($_POST['submission_type']) : '';
    $inserted = false;

    // Defesa no servidor para todos os bloqueios que a interface apresenta:
    // permissão do plano, limitação individual com prazo/motivo e suspensão
    // global. Assim um POST manual não consegue contornar o tema.
    $service_rules = [
        'audio_site'   => [ 'permission' => 'site',   'block' => 'block_promotions',        'global' => 'site',   'label' => 'publicação de músicas no site' ],
        'video_social' => [ 'permission' => 'social', 'block' => 'block_promotions',        'global' => 'social', 'label' => 'promoção nas redes sociais' ],
        'win_video'    => [ 'permission' => 'video',  'block' => 'block_video_applications', 'global' => 'video',  'label' => 'candidatura a videoclipe' ],
    ];
    if ( ! isset( $service_rules[ $submission_type ] ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = [ 'error', 'Tipo de envio inválido.' ];
        wp_redirect( $redirect_url ); exit;
    }
    $service_rule = $service_rules[ $submission_type ];
    $wallet_extra_raw = $wpdb->get_var( $wpdb->prepare(
        "SELECT extra_data FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s",
        $telemovel
    ) );
    $wallet_extra = $wallet_extra_raw ? json_decode( (string) $wallet_extra_raw, true ) : [];
    if ( ! is_array( $wallet_extra ) ) $wallet_extra = [];
    $vip_permissions = isset( $wallet_extra['vip_permissions'] ) && is_array( $wallet_extra['vip_permissions'] )
        ? $wallet_extra['vip_permissions']
        : [ 'distribute' => 1, 'site' => 1, 'social' => 1, 'video' => 1 ];
    if ( empty( $vip_permissions[ $service_rule['permission'] ] ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = [ 'error', 'O teu plano VIP não inclui ' . $service_rule['label'] . '.' ];
        wp_redirect( $redirect_url ); exit;
    }
    $service_block = function_exists( 'rmbz_service_blocked_message' )
        ? rmbz_service_blocked_message( $telemovel, $service_rule['block'], $service_rule['global'] )
        : null;
    if ( $service_block !== null ) {
        $_SESSION['rmbz_withdrawal_notice'] = [ 'error', $service_block ];
        wp_redirect( $redirect_url ); exit;
    }

    if ( $submission_type === 'audio_site' ) {
        
        $audio_url = isset($_POST['audio_file_url']) ? esc_url_raw($_POST['audio_file_url']) : '';
        $cover_url = '';
        if ( !empty($_FILES['cover_image']['name']) ) $cover_url = rmbz_handle_proof_upload('cover_image');

        $is_album = isset($_POST['is_album']) && $_POST['is_album'] === 'yes' ? true : false;
        $album_tracks = [];

        if ($is_album) { 
            $audio_url = 'Álbum/EP (Múltiplas Faixas)'; 
            
            if (isset($_POST['album_track_titles']) && isset($_FILES['album_track_files'])) {
                $titles = (array) $_POST['album_track_titles'];
                $files = $_FILES['album_track_files'];
                
                if ( ! function_exists( 'wp_handle_upload' ) ) {
                    require_once( ABSPATH . 'wp-admin/includes/file.php' );
                }

                // [SEC-FH5] Validação MIME real (finfo) + extensão antes de aceitar
                // o ficheiro. Antes wp_handle_upload era invocado SEM mimes
                // restritos, deixando passar qualquer tipo permitido pelo WP.
                $allowed_mime = ['audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/x-wav', 'audio/wave', 'audio/x-pn-wav'];
                $allowed_ext  = ['mp3', 'wav'];
                $count = count($titles);
                // Limitar nº máximo de faixas por álbum (defesa anti-DoS).
                $count = min($count, 30);

                for ($i = 0; $i < $count; $i++) {
                    if ( empty($titles[$i]) || empty($files['name'][$i]) ) continue;
                    if ( ! empty($files['error'][$i]) && $files['error'][$i] !== UPLOAD_ERR_OK ) continue;
                    if ( ! is_uploaded_file($files['tmp_name'][$i]) ) continue;

                    // Tamanho 50MB máx
                    if ( (int)$files['size'][$i] > 50 * 1024 * 1024 ) continue;
                    if ( (int)$files['size'][$i] < 1024 ) continue;

                    $ext = strtolower( pathinfo($files['name'][$i], PATHINFO_EXTENSION) );
                    if ( ! in_array( $ext, $allowed_ext, true ) ) continue;

                    if ( function_exists('finfo_open') ) {
                        $finfo = finfo_open( FILEINFO_MIME_TYPE );
                        $real_mime = finfo_file( $finfo, $files['tmp_name'][$i] );
                        finfo_close( $finfo );
                        if ( ! in_array( $real_mime, $allowed_mime, true ) ) continue;
                    }

                    // Renomear para evitar shell-meta no path.
                    $safe_name = 'albumtrack_' . wp_generate_password(16, false, false) . '.' . $ext;

                    $_FILES['temp_album_track'] = [
                        'name'     => $safe_name,
                        'type'     => $files['type'][$i],
                        'tmp_name' => $files['tmp_name'][$i],
                        'error'    => $files['error'][$i],
                        'size'     => $files['size'][$i]
                    ];
                    
                    $upload_overrides = [
                        'test_form' => false,
                        'mimes'     => ['mp3' => 'audio/mpeg', 'wav' => 'audio/wav'],
                    ];
                    $movefile = wp_handle_upload( $_FILES['temp_album_track'], $upload_overrides );
                    
                    if ( $movefile && empty($movefile['error']) && ! empty($movefile['url']) ) {
                        $album_tracks[] = [
                            'title' => sanitize_text_field($titles[$i]),
                            'url'   => esc_url_raw($movefile['url'])
                        ];
                    }

                    // Limpar a key temporária
                    unset($_FILES['temp_album_track']);
                }
            }

            if (empty($album_tracks)) {
                $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro: Não foi possível carregar o Álbum. Adicione pelo menos uma música válida (MP3 ou WAV até 50MB).'];
                wp_redirect( $redirect_url ); exit;
            }

        } else {
            if ( empty($audio_url) || empty($cover_url) ) {
                $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro: Ficheiro de Áudio ou Capa em falta. Aguarde a barra de upload concluir!'];
                wp_redirect( $redirect_url ); exit;
            }
        }

        $youtube_link = isset($_POST['youtube_link']) ? esc_url_raw($_POST['youtube_link']) : '';
        $spotify_link = isset($_POST['spotify_link']) ? esc_url_raw($_POST['spotify_link']) : '';
        $apple_link   = isset($_POST['apple_music_link']) ? esc_url_raw($_POST['apple_music_link']) : '';
        
        if (!rmbz_validar_link_plataforma($youtube_link, 'youtube')) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'ERRO DE LINK: O Link do Videoclipe tem de ser do YouTube (youtube.com ou youtu.be)'];
            wp_redirect( $redirect_url ); exit;
        }
        if (!rmbz_validar_link_plataforma($spotify_link, 'spotify')) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'ERRO DE LINK: O Link do Spotify tem de ser oficial'];
            wp_redirect( $redirect_url ); exit;
        }
        if (!rmbz_validar_link_plataforma($apple_link, 'apple')) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'ERRO DE LINK: O Link da Apple Music tem de ser oficial'];
            wp_redirect( $redirect_url ); exit;
        }

        $extra_data = [
            'is_album'       => $is_album,
            'album_tracks'   => $album_tracks,
            'artist_name'    => isset($_POST['artist_name']) ? sanitize_text_field($_POST['artist_name']) : '',
            'has_feat'       => isset($_POST['has_feat']) ? sanitize_text_field($_POST['has_feat']) : '',
            'feat_name'      => isset($_POST['feat_name']) ? sanitize_text_field($_POST['feat_name']) : '',
            'release_date'   => isset($_POST['release_date']) ? sanitize_text_field($_POST['release_date']) : '',
            'has_video'      => isset($_POST['has_video']) ? sanitize_text_field($_POST['has_video']) : '',
            'youtube_link'   => $youtube_link,
            'on_platforms'   => isset($_POST['on_platforms']) ? sanitize_text_field($_POST['on_platforms']) : '',
            'spotify_link'   => $spotify_link,
            'apple_link'     => $apple_link,
            'social_link'    => isset($_POST['social_link']) ? esc_url_raw($_POST['social_link']) : '',
            'description'    => isset($_POST['submission_concept']) ? sanitize_textarea_field($_POST['submission_concept']) : '',
            'cover_image'    => $cover_url
        ];

        $inserted = $wpdb->insert(
            $table_submissions,
            [
                'artist_telemovel' => $telemovel,
                'music_title'      => isset($_POST['music_title']) ? sanitize_text_field($_POST['music_title']) : '',
                'music_file_url'   => $audio_url,
                'music_genre'      => isset($_POST['music_genre']) ? sanitize_text_field($_POST['music_genre']) : '',
                'scenario_type'    => 'Publicação Site',
                'review_status'    => 'pendente',
                'submission_date'  => current_time('mysql'),
                'extra_data'       => wp_json_encode($extra_data)
            ]
        );

    } elseif ( $submission_type === 'video_social' ) {
        
        $thumb_url = '';
        if ( !empty($_FILES['video_thumbnail']['name']) ) $thumb_url = rmbz_handle_proof_upload('video_thumbnail');

        $channels = isset($_POST['dist_channels']) ? array_map('sanitize_text_field', $_POST['dist_channels']) : [];
        $video_title  = isset($_POST['video_title']) ? sanitize_text_field($_POST['video_title']) : 'Vídeo sem título';
        $video_artist = isset($_POST['video_artist_name']) ? sanitize_text_field($_POST['video_artist_name']) : '';

        $video_link_hd = isset($_POST['video_link_url']) ? esc_url_raw($_POST['video_link_url']) : '';
        if (!rmbz_validar_link_plataforma($video_link_hd, 'drive')) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'ERRO DE LINK: O link de Arquivo HD deve ser do Google Drive, Dropbox, WeTransfer ou Mega.'];
            wp_redirect( $redirect_url ); exit;
        }

        $extra_data = [
            'artist_name'    => $video_artist, 
            'video_link_hd'  => $video_link_hd,
            'thumbnail_url'  => $thumb_url,
            'channels'       => implode(', ', $channels),
            'has_feat'       => isset($_POST['video_has_feat']) ? sanitize_text_field($_POST['video_has_feat']) : '',
            'feat_name'      => isset($_POST['video_feat_name']) ? sanitize_text_field($_POST['video_feat_name']) : '',
            'release_date'   => isset($_POST['video_release_date']) ? sanitize_text_field($_POST['video_release_date']) : '',
            'social_caption' => isset($_POST['social_caption']) ? sanitize_textarea_field($_POST['social_caption']) : ''
        ];

        $inserted = $wpdb->insert(
            $table_submissions,
            [
                'artist_telemovel' => $telemovel,
                'music_title'      => $video_title,
                'music_file_url'   => '', 
                'music_genre'      => isset($_POST['video_genre']) ? sanitize_text_field($_POST['video_genre']) : 'Não definido',
                'scenario_type'    => 'Redes Sociais',
                'review_status'    => 'pendente',
                'submission_date'  => current_time('mysql'),
                'extra_data'       => wp_json_encode($extra_data)
            ]
        );

    } elseif ( $submission_type === 'win_video' ) {
        
        $demo_url = isset($_POST['audio_file_project_url']) ? esc_url_raw($_POST['audio_file_project_url']) : '';
        $project_title = isset($_POST['project_title']) ? sanitize_text_field($_POST['project_title']) : '';

        if ( empty($demo_url) ) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'A Demo MP3 é obrigatória para avaliação. Aguarde o upload!'];
            wp_redirect( $redirect_url ); exit;
        }

        $ref_link = isset($_POST['project_link_opt']) ? esc_url_raw($_POST['project_link_opt']) : '';
        if (!rmbz_validar_link_plataforma($ref_link, 'youtube')) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'ERRO DE LINK: Se fornecer um link de referência de vídeo, ele tem de ser obrigatoriamente do YouTube.'];
            wp_redirect( $redirect_url ); exit;
        }
        if ( function_exists( 'rmbz_filming_is_cancelled_music_blocked' )
             && rmbz_filming_is_cancelled_music_blocked( $telemovel, $project_title, $demo_url ) ) {
            $_SESSION['rmbz_withdrawal_notice'] = [
                'error',
                'Esta música já teve um projecto cancelado por falta de confirmação e não pode ser reenviada.'
            ];
            wp_redirect( $redirect_url ); exit;
        }

        // [1.5.398] Participação (feat) — nome + tem conta? + número.
        // [1.5.401] Com conta 1MZ: a conta é VERIFICADA e o participante terá
        // de aceitar o convite (recusa cancela o projeto).
        $rmbz_proj_extra = [];
        if ( ! empty($_POST['feat_enabled']) ) {
            $rmbz_feat_name = isset($_POST['feat_name']) ? sanitize_text_field($_POST['feat_name']) : '';
            $rmbz_feat_has  = ! empty($_POST['feat_has_account']);
            $rmbz_feat_tel  = isset($_POST['feat_tel']) ? preg_replace('/[^0-9+]/', '', (string) $_POST['feat_tel']) : '';
            if ( $rmbz_feat_has && function_exists('rmbz_feat_check_account') ) {
                $rmbz_feat_chk = rmbz_feat_check_account( $rmbz_feat_tel );
                if ( ! $rmbz_feat_chk['exists'] ) {
                    $_SESSION['rmbz_withdrawal_notice'] = ['error', 'O número da conta do participante (feat) não foi encontrado na plataforma. Verifica o número ou desmarca "tem conta 1MZ".'];
                    wp_redirect( $redirect_url ); exit;
                }
                if ( $rmbz_feat_chk['tel'] === (string) $telemovel ) {
                    $_SESSION['rmbz_withdrawal_notice'] = ['error', 'O participante não pode ser a tua própria conta.'];
                    wp_redirect( $redirect_url ); exit;
                }
                $rmbz_feat_tel = $rmbz_feat_chk['tel'];
            }
            if ( $rmbz_feat_name !== '' ) {
                $rmbz_proj_extra['feat'] = [
                    'name'        => $rmbz_feat_name,
                    'has_account' => $rmbz_feat_has,
                    'tel'         => $rmbz_feat_has ? $rmbz_feat_tel : '',
                ];
            }
        }

        $inserted = $wpdb->insert(
            $table_projects,
            [
                'artist_telemovel'  => $telemovel,
                'project_title'     => $project_title,
                'music_producer'    => isset($_POST['music_producer']) ? sanitize_text_field($_POST['music_producer']) : '',
                'project_pitch'     => isset($_POST['project_pitch']) ? sanitize_textarea_field($_POST['project_pitch']) : '',
                'demo_mp3_url'      => $demo_url,
                'project_link_opt'  => $ref_link,
                'scenario_type'     => isset($_POST['video_scenario']) ? sanitize_text_field($_POST['video_scenario']) : '',
                'scenario_cost'     => 0,
                'production_status' => 'pending_review',
                'extra_data'        => ! empty($rmbz_proj_extra) ? wp_json_encode($rmbz_proj_extra) : null,
                'contract_date'     => current_time('mysql')
            ]
        );
    }

    // 3. Resultado Final e Gatilho de E-mails
    if ( $inserted ) {
        $novo_id = $wpdb->insert_id; 

        if ( $submission_type === 'audio_site' ) {
            do_action( 'rmbz_site_submission_created', (int) $novo_id );
        }
        
        if ( $submission_type === 'audio_site' || $submission_type === 'video_social' ) {
            if ( function_exists('onemz_send_submission_notification') ) {
                onemz_send_submission_notification( $novo_id );
            }
        } elseif ( $submission_type === 'win_video' ) {

            // [1.5.401] Feat com conta 1MZ → convida o participante (todos os
            // canais). Ele aceita (com termos) ou recusa (cancela o projeto).
            if ( function_exists('rmbz_feat_invite_create') ) {
                rmbz_feat_invite_create( (int) $novo_id );
            }

            // ====================================================================
            // BUSCAR O E-MAIL CONFIGURADO PARA NOTIFICAÇÕES (O MESMO DAS MÚSICAS)
            // ====================================================================
            $admin_email = get_option('admin_email'); // E-mail padrão de segurança
            
            // Tenta ir buscar às configurações da plataforma
            $email_settings = get_option('rmbz_email_settings');
            if ( !empty($email_settings['notification_email']) && is_email($email_settings['notification_email']) ) {
                $admin_email = $email_settings['notification_email'];
            } elseif ( !empty($email_settings['admin_notification_email']) && is_email($email_settings['admin_notification_email']) ) {
                $admin_email = $email_settings['admin_notification_email'];
            } elseif ( get_option('rmbz_notification_email') ) {
                $admin_email = get_option('rmbz_notification_email');
            }
            
            // Constrói e envia o E-mail de Aviso
            $subject = '🎥 Nova Candidatura a Videoclipe (1MZ)!';
            $music_title = isset($_POST['project_title']) ? sanitize_text_field($_POST['project_title']) : '';
            $scenario = isset($_POST['video_scenario']) ? sanitize_text_field($_POST['video_scenario']) : '';
            
            $body = "<div style='font-family: Arial; padding: 20px; background: #1a1a1a; color: #fff; border-radius: 8px;'>
                        <h2 style='color: #f0b90b;'>Nova Candidatura de Videoclipe</h2>
                        <p>O artista com o número <strong>{$telemovel}</strong> submeteu uma nova candidatura para gravação de vídeo.</p>
                        <ul>
                            <li><strong>Música:</strong> {$music_title}</li>
                            <li><strong>Nível Selecionado:</strong> {$scenario}</li>
                        </ul>
                        <p>Aceda ao 1MZ Manager para ouvir a Demo MP3 e aprovar o projeto!</p>
                     </div>";
            
            // ====================================================================
            // ENVIO DE E-MAIL COM CABEÇALHOS OFICIAIS (ANTI-SPAM)
            // ====================================================================
            if (function_exists('rmbz_build_html_email')) {
                $tpl = get_option('rmbz_email_templates');
                $sender_name = !empty($tpl['sender_name']) ? $tpl['sender_name'] : get_bloginfo('name');
                $sender_email = is_email($tpl['sender_email'] ?? '') ? $tpl['sender_email'] : get_option('admin_email');
                
                $html_body = rmbz_build_html_email($body, $sender_name);
                $headers = ['Content-Type: text/html; charset=UTF-8', 'From: ' . $sender_name . ' <' . $sender_email . '>'];
                wp_mail($admin_email, $subject, $html_body, $headers);
            } else {
                $headers = ['Content-Type: text/html; charset=UTF-8'];
                wp_mail($admin_email, $subject, $body, $headers);
            }
        }

        $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Submissão enviada com sucesso! Aguarde a nossa análise.'];
    } else {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Ocorreu um erro ao guardar na base de dados.'];
    }
    
    wp_redirect( $redirect_url );
    exit;
}
add_action('admin_post_rmbz_handle_frontend_upload', 'rmbz_handle_frontend_upload');
add_action('admin_post_nopriv_rmbz_handle_frontend_upload', 'rmbz_handle_frontend_upload');

/**
 * ==========================================================================
 * 3. PROCESSAR PAGAMENTO DE SUBSCRIÇÃO
 * ==========================================================================
 */
function rmbz_processar_pagamento_subscricao() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Não autorizado.');

    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'rmbz_pay_sub_nonce' ) ) {
        wp_die('Falha de segurança.');
    }

    $user_phone = rmbz_get_current_user_telemovel();
    $result = rmbz_process_subscription_payment( $user_phone );

    if ( $result['success'] ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['success', $result['message']];
    } else {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', $result['message']];
    }
    
    wp_redirect( wp_get_referer() );
    exit;
}
add_action('admin_post_rmbz_pay_subscription', 'rmbz_processar_pagamento_subscricao');
add_action('admin_post_nopriv_rmbz_pay_subscription', 'rmbz_processar_pagamento_subscricao');

/**
 * ==========================================================================
 * 4. PROCESSAR DEPÓSITOS E SALDOS
 * ==========================================================================
 */
function rmbz_processar_deposito() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Não autorizado.');
    $redirect_url = wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/');
    
    if ( ! isset( $_POST['_rmbz_deposit_nonce'] ) || ! wp_verify_nonce( $_POST['_rmbz_deposit_nonce'], 'rmbz_deposit_nonce' ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Segurança expirada. Tente novamente.'];
        wp_redirect( $redirect_url ); exit;
    }

    $user_phone = rmbz_get_current_user_telemovel();
    $amount = isset($_POST['deposit_amount']) ? (float) sanitize_text_field($_POST['deposit_amount']) : 0;
    $method = isset($_POST['payment_method']) ? sanitize_text_field($_POST['payment_method']) : '';
    $sender_phone = isset($_POST['sender_phone']) ? sanitize_text_field($_POST['sender_phone']) : '';
    $proof_type = isset($_POST['proof_type']) ? sanitize_text_field($_POST['proof_type']) : ''; 
    
    $transaction_id = '';
    $proof_image = '';

    if ($amount > 50000) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Valor excede o limite.'];
        wp_redirect( $redirect_url ); exit;
    }

    if ( $proof_type === 'id' ) {
        $transaction_id = isset($_POST['transaction_id']) ? sanitize_text_field($_POST['transaction_id']) : '';
        if ( empty($transaction_id) ) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'ID da transação obrigatório.'];
            wp_redirect( $redirect_url ); exit;
        }
    } else {
        if ( !empty($_FILES['proof_image']['name']) ) {
            $url = rmbz_handle_proof_upload('proof_image');
            if ( $url ) { $proof_image = $url; } else {
                $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro ao enviar imagem.'];
                wp_redirect( $redirect_url ); exit;
            }
        } else {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Imagem obrigatória.'];
            wp_redirect( $redirect_url ); exit;
        }
    }

    global $wpdb;
    $table_deposits = $wpdb->prefix . 'rmbz_deposit_requests';

    $existing_pending = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$table_deposits} WHERE user_telemovel = %s AND status = 'pendente'", $user_phone ) );

    if ( $existing_pending ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Já possui um depósito pendente em análise.'];
        wp_redirect( $redirect_url ); exit;
    }

    $inserted = $wpdb->insert(
        $table_deposits,
        [
            'user_telemovel'   => $user_phone,
            'amount'           => $amount,
            'status'           => 'pendente',
            'payment_method'   => $method,
            'transaction_id'   => $transaction_id,
            'proof_image'      => $proof_image,
            'sender_phone'     => $sender_phone,
            'request_date'     => current_time('mysql', 1),
            // [1.6.118] Top-up posterior — quase sempre is_first_deposit=0
            // mas usamos o helper para safety (cobre user que reinstala app).
            'source_platform'  => 'site',
            'is_first_deposit' => function_exists('rmbz_is_first_deposit_for_user')
                && rmbz_is_first_deposit_for_user( $user_phone ) ? 1 : 0,
        ],
        ['%s', '%f', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d']
    );

    if ($inserted) {
        $novo_deposito_id = $wpdb->insert_id;
        if (empty($novo_deposito_id)) {
            $novo_deposito_id = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$table_deposits} WHERE user_telemovel = %s ORDER BY id DESC LIMIT 1", $user_phone));
        }

        if ( function_exists('rmbz_send_admin_deposit_alert') ) {
            $user_name = $wpdb->get_var($wpdb->prepare("SELECT user_nome FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s", $user_phone));
            $nome_final = $user_name ? $user_name : $user_phone;
            $tx_display = !empty($transaction_id) ? $transaction_id : 'Imagem/Screenshot (Ver no Painel)';
            rmbz_send_admin_deposit_alert($nome_final, $amount, $method, $tx_display, $novo_deposito_id);
        }
        $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Pedido de depósito enviado com sucesso! Aguarde aprovação.'];
    } else {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro técnico ao registar depósito.'];
    }
    wp_redirect( $redirect_url ); exit;
} 
add_action('admin_post_rmbz_processar_deposito', 'rmbz_processar_deposito');
add_action('admin_post_nopriv_rmbz_processar_deposito', 'rmbz_processar_deposito');

/**
 * ==========================================================================
 * 5. FEEDBACK DE PROJETOS E PAGAMENTO DE VIDEOCLIPE
 * ==========================================================================
 */
function onemz_update_feedback() {
    // [1.6.363] Nonce (CSRF) — faltava. Sessão e ownership já existiam abaixo.
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce( $_POST['_wpnonce'], 'onemz_update_feedback_nonce' ) ) {
        wp_die('Falha de segurança.');
    }
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');

    $telemovel = rmbz_get_current_user_telemovel();
    $project_id = isset($_POST['project_id']) ? absint($_POST['project_id']) : 0;
    $new_feedback = isset($_POST['artist_feedback']) ? sanitize_textarea_field($_POST['artist_feedback']) : '';

    if ( $project_id === 0 || empty($new_feedback) ) { wp_redirect( wp_get_referer() ); exit; }

    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $project = $wpdb->get_row( $wpdb->prepare("SELECT id, artist_feedback FROM {$table_projects} WHERE id = %d AND artist_telemovel = %s", $project_id, $telemovel) );

    if ( ! $project ) wp_die('Sem permissão.');

    // O chat live é a fonte canónica. Este admin-post fica como fallback
    // para navegadores sem JavaScript, mas grava na mesma tabela REST.
    if ( function_exists('rmbz_pchat_is_chat_locked') && rmbz_pchat_is_chat_locked($project_id) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'O chat deste projeto está desativado.'];
        wp_redirect( wp_get_referer() ); exit;
    }
    if ( function_exists('rmbz_pchat_insert_message_as_artist') ) {
        $message_id = rmbz_pchat_insert_message_as_artist($project_id, $new_feedback, null);
        $_SESSION['rmbz_withdrawal_notice'] = $message_id
            ? ['success', 'Mensagem enviada com sucesso para a equipa!']
            : ['error', 'Não foi possível enviar a mensagem.'];
        wp_redirect( wp_get_referer() ); exit;
    }

    $timestamp = current_time('d/m/Y H:i');
    $entry = "[$timestamp] <strong>Artista:</strong> $new_feedback";

    $updated_history = $project->artist_feedback;
    if ( ! empty($updated_history) ) { $updated_history .= "\n\n" . $entry; } else { $updated_history = $entry; }

    $wpdb->update( $table_projects, ['artist_feedback' => $updated_history], ['id' => $project_id], ['%s'], ['%d'] );
    $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Mensagem enviada com sucesso para a equipa!'];
    wp_redirect( wp_get_referer() ); exit;
}
add_action('admin_post_onemz_update_feedback', 'onemz_update_feedback');
add_action('admin_post_nopriv_onemz_update_feedback', 'onemz_update_feedback');

function onemz_pay_project_cost() {
    $redirect_url = wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/');
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) { wp_redirect(home_url()); exit; }
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'onemz_pay_project_nonce') ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Segurança expirada. Atualize a página.'];
        wp_redirect( $redirect_url ); exit;
    }

    $project_id = isset($_POST['project_id']) ? absint($_POST['project_id']) : 0;
    $telemovel = rmbz_get_current_user_telemovel();

    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $project = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table_projects} WHERE id = %d AND artist_telemovel = %s", $project_id, $telemovel));

    if (!$project) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Projeto inválido.']; wp_redirect( $redirect_url ); exit; }

    // [1.6.118.56] Modo misto: o valor a debitar é o obligatory_cost (só items
    // que o artista NÃO assumiu pessoalmente), NÃO o scenario_cost bruto.
    // Mesma função usada pelo /pay da API — single source of truth.
    $custo_total     = (float) $project->scenario_cost;
    $obligatory_cost = function_exists('rmbz_calc_project_obligatory_cost')
        ? rmbz_calc_project_obligatory_cost($project)
        : $custo_total; // fallback se helper não estiver carregado por alguma razão
    $ja_pago         = (float) $project->amount_paid;
    $valor_a_pagar   = $obligatory_cost - $ja_pago;

    if ($valor_a_pagar <= 0) { $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Este projeto já está totalmente pago.']; wp_redirect( $redirect_url ); exit; }

    $saldo_carteira = rmbz_get_wallet_balance_by_phone($telemovel);
    
    if ($saldo_carteira < $valor_a_pagar) {
        // [1.6.118.56] BUG fix — antes mostrava $valor_a_pagar inteiro como
        // "faltam X" em vez de calcular o défice real (valor_a_pagar - saldo).
        $falta_real = $valor_a_pagar - $saldo_carteira;
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Saldo insuficiente. Faltam ' . number_format($falta_real, 2, ',', '.') . ' MT na carteira.'];
        wp_redirect( $redirect_url ); exit;
    }

    $details = ($ja_pago == 0) ? "Pagamento Inicial de Produção (Projeto #$project_id)" : "Pagamento Adicional de Produção (Projeto #$project_id)";
    $debit = rmbz_update_wallet_balance($telemovel, -$valor_a_pagar, 'production_payment', $project_id, $details);

    if ($debit['success']) {
        $novo_total_pago = $ja_pago + $valor_a_pagar;
        // [1.6.118.56] is_paid usa obligatory_cost (caso contrário projecto em
        // modo misto nunca atinge custo_total bruto e fica eternamente unpaid).
        $esta_pago = ($novo_total_pago >= ($obligatory_cost - 0.01)) ? 1 : 0;
        $wpdb->update($table_projects, ['amount_paid' => $novo_total_pago, 'is_paid' => $esta_pago, 'production_status' => 'filming'], ['id' => $project_id], ['%f', '%d', '%s'], ['%d']);
        $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Pagamento do videoclipe concluído com sucesso!'];
    } else {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Erro técnico ao debitar saldo.'];
    }
    wp_redirect( $redirect_url ); exit;
}
add_action('admin_post_onemz_pay_project_cost', 'onemz_pay_project_cost');
add_action('admin_post_nopriv_onemz_pay_project_cost', 'onemz_pay_project_cost');

/**
 * [1.6.388] Pagar a MULTA por atraso do videoclipe com o saldo (site).
 * Reutiliza rmbz_project_pay_fine_from_wallet (valida PIN, debita, limpa dívida).
 */
function rmbz_site_pay_project_fine() {
    $redirect_url = wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/');
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) { wp_redirect(home_url()); exit; }
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'rmbz_pay_fine_nonce') ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Segurança expirada. Atualize a página.'];
        wp_redirect( $redirect_url ); exit;
    }

    $telemovel = rmbz_get_current_user_telemovel();
    $pin       = isset($_POST['pin']) ? (string) $_POST['pin'] : '';

    if ( ! function_exists('rmbz_project_pay_fine_from_wallet') ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Função indisponível.'];
        wp_redirect( $redirect_url ); exit;
    }

    $res = rmbz_project_pay_fine_from_wallet( $telemovel, $pin );
    $_SESSION['rmbz_withdrawal_notice'] = [
        ! empty($res['success']) ? 'success' : 'error',
        (string) ( $res['message'] ?? 'Não foi possível pagar a multa.' ),
    ];
    wp_redirect( $redirect_url ); exit;
}
add_action('admin_post_rmbz_pay_project_fine', 'rmbz_site_pay_project_fine');
add_action('admin_post_nopriv_rmbz_pay_project_fine', 'rmbz_site_pay_project_fine');

/**
 * ==========================================================================
 * 6. RETIRADA DE ROYALTIES E DISTRIBUIÇÃO AJAX
 * ==========================================================================
 */
function rmbz_processar_retirada_royalties() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');
    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'rmbz_withdraw_usd_nonce' ) ) wp_die('Link expirado.');

    $telemovel = rmbz_get_current_user_telemovel();
    $amount_usd = isset($_POST['amount_usd']) ? (float)$_POST['amount_usd'] : 0;
    
    require_once RMBZ_PLUGIN_PATH . 'includes/distribution/distribution-financial.php';
    $resultado = rmbz_secure_transfer_usd_to_mt( $telemovel, $amount_usd );

    $redirect_url = wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/');
    
    if ( $resultado['success'] ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['success', $resultado['message']];
    } else {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', $resultado['message']];
    }
    wp_redirect( $redirect_url ); exit;
}
add_action('admin_post_rmbz_withdraw_royalties', 'rmbz_processar_retirada_royalties');
add_action('admin_post_nopriv_rmbz_withdraw_royalties', 'rmbz_processar_retirada_royalties');

function onemz_save_release_draft_ajax() {
    // Aceitar nonce em 'nonce' OU '_wpnonce' (dependendo de qual o form usa)
    $nonce_valid = check_ajax_referer('rmbz_distro_nonce', 'nonce', false)
                || check_ajax_referer('rmbz_distro_nonce', '_wpnonce', false);
    if ( ! $nonce_valid ) {
        wp_send_json_error('Falha de segurança (nonce inválido).');
    }
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) {
        wp_send_json_error('Sessão expirada.');
    }

    $telemovel = rmbz_get_current_user_telemovel();
    if ( empty($telemovel) ) {
        wp_send_json_error('Utilizador sem telemóvel associado.');
    }

    global $wpdb;
    $table_releases = $wpdb->prefix . 'rmbz_distro_releases';

    // Verificar tabela existe
    if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_releases'" ) !== $table_releases ) {
        wp_send_json_error('Tabela de releases não existe. Contacte o administrador.');
    }

    $release_id = isset($_POST['release_id']) ? intval($_POST['release_id']) : 0;
    $title = isset($_POST['release_title']) ? sanitize_text_field($_POST['release_title']) : '';
    $lang  = isset($_POST['language'])      ? sanitize_text_field($_POST['language']) : '';
    $genre = isset($_POST['primary_genre']) ? sanitize_text_field($_POST['primary_genre']) : '';
    $date  = isset($_POST['release_date'])  ? sanitize_text_field($_POST['release_date']) : '';
    $label = isset($_POST['label_name'])    ? sanitize_text_field($_POST['label_name']) : '';
    $loc   = isset($_POST['recording_location']) ? sanitize_text_field($_POST['recording_location']) : '';
    $upc   = isset($_POST['upc_code'])      ? sanitize_text_field($_POST['upc_code']) : '';

    if ( empty($title) ) wp_send_json_error('Título obrigatório.');

    $cover_image_url = '';
    if ( ! empty($_FILES['cover_art_file']['name']) ) {
        if ( function_exists('rmbz_handle_proof_upload') ) {
            $uploaded = rmbz_handle_proof_upload('cover_art_file');
            if ( $uploaded ) $cover_image_url = $uploaded;
        }
    }

    // Construir dados + formatos em paralelo — SEMPRE sincronizados
    $data_to_save = [
        'artist_telemovel'   => $telemovel,
        'title'              => $title,
        'language'           => $lang,
        'primary_genre'      => $genre,
        'release_date'       => $date,
        'label_name'         => $label,
        'recording_location' => $loc,
        'upc_code'           => $upc,
        'status'             => 'incomplete',
    ];
    $format = [ '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ];

    if ( ! empty($cover_image_url) ) {
        $data_to_save['cover_image'] = $cover_image_url;
        $format[] = '%s';
    }

    if ( $release_id > 0 ) {
        // UPDATE — verificar ownership
        $owner = $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM $table_releases WHERE id = %d AND artist_telemovel = %s",
            $release_id, $telemovel
        ) );
        if ( ! $owner ) wp_send_json_error('Lançamento não encontrado.');

        $result = $wpdb->update( $table_releases, $data_to_save, [ 'id' => $release_id ], $format, [ '%d' ] );
        if ( $result === false ) {
            wp_send_json_error( 'Erro ao actualizar: ' . $wpdb->last_error );
        }
        wp_send_json_success( [ 'message' => 'Rascunho atualizado', 'release_id' => $release_id ] );
    } else {
        // INSERT — criar novo
        $result = $wpdb->insert( $table_releases, $data_to_save, $format );
        if ( $result === false ) {
            wp_send_json_error( 'Erro ao criar: ' . $wpdb->last_error );
        }
        $new_id = (int) $wpdb->insert_id;
        if ( $new_id <= 0 ) {
            wp_send_json_error( 'Insert retornou ID inválido. Último erro: ' . $wpdb->last_error );
        }
        wp_send_json_success( [ 'message' => 'Rascunho criado', 'release_id' => $new_id ] );
    }
}
add_action('wp_ajax_onemz_save_release_draft', 'onemz_save_release_draft_ajax');
add_action('wp_ajax_nopriv_onemz_save_release_draft', 'onemz_save_release_draft_ajax');

function onemz_finalize_release_ajax() {
    if ( ! check_ajax_referer('rmbz_distro_nonce', 'nonce', false) ) wp_send_json_error('Segurança.');
    $telemovel = rmbz_get_current_user_telemovel();
    $release_id = isset($_POST['release_id']) ? intval($_POST['release_id']) : 0;
    global $wpdb;
    $table_releases = $wpdb->prefix . 'rmbz_distro_releases';

    $release = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, status FROM $table_releases WHERE id = %d AND artist_telemovel = %s",
        $release_id, $telemovel
    ) );
    if ( ! $release ) wp_send_json_error('Erro de permissão ou lançamento não encontrado.');

    // Estados que NÃO permitem re-submit
    $locked = ['live', 'distribuido', 'takedown_requested', 'taken_down'];
    if ( in_array($release->status, $locked, true) ) {
        wp_send_json_error('Este lançamento já está em distribuição e não pode ser re-submetido aqui.');
    }

    // Re-submit de um lançamento devolvido
    if ( $release->status === 'returned' && function_exists('rmbz_distro_resubmit_release') ) {
        $result = rmbz_distro_resubmit_release( $release_id, $telemovel );
        if ( is_wp_error($result) ) {
            wp_send_json_error( $result->get_error_message() );
        }
        wp_send_json_success([
            'message' => '✓ Correcções submetidas. O administrador vai rever novamente.',
            'resubmit' => true,
        ]);
    }

    // Fluxo normal: incomplete/rejected → pendente
    $now = current_time('mysql');
    $wpdb->update(
        $table_releases,
        [ 'status' => 'pendente', 'submitted_at' => $now ],
        [ 'id' => $release_id ],
        [ '%s', '%s' ],
        [ '%d' ]
    );

    // Log de auditoria
    if ( function_exists('rmbz_admin_log_status_change') ) {
        rmbz_admin_log_status_change( $release_id, $release->status, 'pendente', 'Submetido pelo artista' );
    }

    wp_send_json_success(['message' => 'Lançamento enviado com sucesso!']);
}
add_action('wp_ajax_onemz_finalize_release', 'onemz_finalize_release_ajax');
add_action('wp_ajax_nopriv_onemz_finalize_release', 'onemz_finalize_release_ajax');

function onemz_delete_release_action() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');
    if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'rmbz_delete_release_nonce' ) ) wp_die('Link expirado.');

    $telemovel = rmbz_get_current_user_telemovel();
    $access_error = function_exists( 'rmbz_distro_artist_access_error' )
        ? rmbz_distro_artist_access_error( $telemovel )
        : '';
    if ( $access_error !== '' ) wp_die( esc_html( $access_error ), 'Distribuição indisponível', [ 'response' => 403 ] );
    $release_id = isset($_GET['release_id']) ? intval($_GET['release_id']) : 0;
    $redirect_url = ( isset( $_GET['redirect'] ) && sanitize_key( wp_unslash( $_GET['redirect'] ) ) === 'vip' )
        ? home_url( '/minha-conta/?sect=distro' )
        : home_url( '/dashboard-digital/' );
    global $wpdb;
    $table_releases = $wpdb->prefix . 'rmbz_distro_releases';
    $table_tracks   = $wpdb->prefix . 'rmbz_distro_tracks';

    // [BUG #10] Buscamos os URLs ANTES de apagar — precisamos para remover do disco
    $release = $wpdb->get_row($wpdb->prepare(
        "SELECT status, cover_image FROM $table_releases WHERE id = %d AND artist_telemovel = %s",
        $release_id, $telemovel
    ));
    if ( ! $release ) wp_die('Lançamento não encontrado.');
    if ( ! in_array( (string) $release->status, [ 'incomplete', 'draft' ], true ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Não é possível apagar um lançamento nas lojas.'];
        wp_safe_redirect( $redirect_url ); exit;
    }

    // [BUG #10] Recolher URLs dos áudios antes de apagar os registos
    $track_urls = $wpdb->get_col( $wpdb->prepare(
        "SELECT audio_url FROM $table_tracks WHERE release_id = %d AND audio_url IS NOT NULL AND audio_url != ''",
        $release_id
    ));

    // Apagar registos da BD
    $wpdb->delete($table_tracks,   ['release_id' => $release_id], ['%d']);
    $wpdb->delete($table_releases, ['id' => $release_id],         ['%d']);

    // [1.5.187] Hook para sistemas que dependem do release (notificações,
    // cleanup de ficheiros, audit logs, etc.).
    do_action( 'rmbz_release_deleted', (int) $release_id, (string) $telemovel );

    // [BUG #10] Só agora, após a BD estar limpa, apagamos os ficheiros físicos.
    // Se falharem, o pior cenário é lixo no disco (não inconsistência de dados).
    if ( function_exists('rmbz_destruir_ficheiro_fisico') ) {
        if ( ! empty($release->cover_image) ) {
            rmbz_destruir_ficheiro_fisico( $release->cover_image );
        }
        foreach ( (array) $track_urls as $url ) {
            if ( ! empty($url) ) {
                rmbz_destruir_ficheiro_fisico( $url );
            }
        }
    }

    $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Rascunho de lançamento apagado com sucesso.'];
    wp_safe_redirect( $redirect_url ); exit;
}
add_action('admin_post_onemz_delete_release', 'onemz_delete_release_action');
add_action('admin_post_nopriv_onemz_delete_release', 'onemz_delete_release_action');

/**
 * ==========================================================================
 * SISTEMA DE CONTRATOS - AÇÃO DO ARTISTA (ACEITAR CONTRATO + KYC)
 * ==========================================================================
 */
function onemz_accept_contract_action() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');
    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'onemz_accept_contract_nonce' ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Falha de segurança. Atualize a página.'];
        wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
    }

    $project_id = intval($_POST['project_id']);
    $real_name = sanitize_text_field($_POST['kyc_real_name']);
    $telemovel = rmbz_get_current_user_telemovel();
    
    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $project = $wpdb->get_row($wpdb->prepare("SELECT project_title, extra_data FROM {$table_projects} WHERE id = %d AND artist_telemovel = %s", $project_id, $telemovel));
    
    if ($project) {
        $extra = !empty($project->extra_data) ? json_decode($project->extra_data, true) : [];
        
        // 1. UPLOAD SEGURO DA FOTO DE IDENTIDADE (KYC)
        $kyc_photo_url = '';
        if ( !empty($_FILES['kyc_signature_photo']['name']) ) {
            if (function_exists('rmbz_handle_proof_upload')) {
                $kyc_photo_url = rmbz_handle_proof_upload('kyc_signature_photo');
            }
        }
        
        if (!$kyc_photo_url) {
            $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Falha ao carregar a foto do BI. Envie uma imagem válida (JPG/PNG) e com menos de 10MB.'];
            wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
        }

        // 2. SALVAR DADOS E ALTERAR ESTADO PARA "REVISÃO KYC"
        $extra['contract_accepted'] = true;
        $extra['contract_rejected'] = false; 
        $extra['contract_accepted_date'] = current_time('mysql');
        $extra['contract_real_name'] = $real_name;
        $extra['contract_kyc_photo'] = $kyc_photo_url;
        $extra['kyc_status'] = 'pending_admin_review';
        $extra['payment_choice'] = isset($_POST['payment_choice']) ? sanitize_text_field($_POST['payment_choice']) : 'pay_producer'; // GUARDA A ESCOLHA DO MODO CHECKLIST

        // [1.6.118.35] Fase 2 — Processar decisões per-item do artista (negociáveis).
        // $_POST['item_assumes'] é um array indexado pelo índice do item em
        // scenario_details: { "0": "1", "2": "0", ... }. Só items must_pay=0
        // têm radio buttons no site; outros vêm em falta e não tocamos.
        $item_assumes_post = isset( $_POST['item_assumes'] ) && is_array( $_POST['item_assumes'] )
            ? $_POST['item_assumes']
            : [];

        if ( ! empty( $item_assumes_post ) ) {
            $proj_full = $wpdb->get_row( $wpdb->prepare(
                "SELECT scenario_details FROM {$table_projects} WHERE id = %d",
                $project_id
            ) );
            $details = ( $proj_full && ! empty( $proj_full->scenario_details ) )
                ? json_decode( $proj_full->scenario_details, true )
                : [];
            if ( ! is_array( $details ) ) $details = [];

            foreach ( $details as $idx => &$item ) {
                $mp = isset( $item['must_pay'] ) ? (int) $item['must_pay'] : 1;
                // Só items negociáveis aceitam decisão do artista
                if ( $mp === 0 && isset( $item_assumes_post[ $idx ] ) ) {
                    $item['artist_assumes'] = (int) $item_assumes_post[ $idx ] === 1 ? 1 : 0;
                } elseif ( $mp === 1 ) {
                    // Coerência: obrigatório nunca tem assume
                    $item['artist_assumes'] = 0;
                }
                // [1.6.118.44] Marca como DECIDED — artista viu a UI de escolha
                // para este item (ou não precisava, se obrigatório).
                $item['decided'] = 1;
            }
            unset( $item );

            $wpdb->update(
                $table_projects,
                [ 'scenario_details' => wp_json_encode( $details ) ],
                [ 'id' => $project_id ]
            );
        }

        $wpdb->update(
            $table_projects, 
            [
                'extra_data' => wp_json_encode($extra),
                'production_status' => 'kyc_review' // Trava o projeto neste estado
            ], 
            ['id' => $project_id]
        );

        // 3. NOTIFICAR O ADMINISTRADOR POR E-MAIL
        $admin_email = get_option('rmbz_admin_notification_email', get_option('admin_email'));
        wp_mail(
            $admin_email, 
            '🚨 KYC Recebido: Valide a Identidade do Artista', 
            "O artista enviou a foto do BI para o videoclipe '{$project->project_title}'.\nVá ao painel 'Gestão de Projetos' aprovar a identidade para desbloquear o pagamento ao artista."
        );

        $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Contrato assinado! A sua identidade está agora em análise pela nossa equipa de segurança.'];
    }
    wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
}
add_action('admin_post_onemz_accept_contract', 'onemz_accept_contract_action');
add_action('admin_post_nopriv_onemz_accept_contract', 'onemz_accept_contract_action');

/**
 * ==========================================================================
 * SISTEMA DE CONTRATOS - AÇÃO DO ARTISTA (RECUSAR CONTRATO)
 * ==========================================================================
 */
function onemz_reject_contract_action() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');
    // [SEC-FH2] Antes não havia nonce — qualquer site externo conseguia, via
    // CSRF, fazer um artista logado rejeitar o contrato dele.
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'onemz_reject_contract_nonce') ) {
        wp_die('Falha de segurança (nonce).');
    }
    $project_id = isset($_POST['project_id']) ? intval($_POST['project_id']) : 0;
    $reason = isset($_POST['rejection_reason']) ? sanitize_text_field( wp_unslash($_POST['rejection_reason']) ) : '';
    $telemovel = rmbz_get_current_user_telemovel();
    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $project = $wpdb->get_row($wpdb->prepare("SELECT extra_data FROM {$table_projects} WHERE id = %d AND artist_telemovel = %s", $project_id, $telemovel));
    if ($project) {
        $extra = !empty($project->extra_data) ? json_decode($project->extra_data, true) : [];
        if ( ! is_array($extra) ) $extra = [];
        $extra['contract_accepted'] = false;
        $extra['contract_rejected'] = true;
        $extra['contract_rejected_reason'] = $reason;
        $wpdb->update($table_projects, ['extra_data' => wp_json_encode($extra)], ['id' => $project_id]);
        if ( session_status() === PHP_SESSION_NONE && ! headers_sent() ) { session_start(); }
        $_SESSION['rmbz_withdrawal_notice'] = ['success', 'A sua objeção foi enviada para a equipa. Aguarde a avaliação da nossa administração.'];
    }
    wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
}
add_action('admin_post_onemz_reject_contract', 'onemz_reject_contract_action');
add_action('admin_post_nopriv_onemz_reject_contract', 'onemz_reject_contract_action');

/**
 * [1.6.118.44] Handler: artista decide items adicionados pelo admin APÓS
 * aceitação do contrato. Mini-prompt — não re-executa KYC nem qualquer outro
 * passo, apenas grava decisões per-item para items com decided=0.
 */
function onemz_decide_pending_items_action() {
    if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'onemz_decide_pending_nonce' ) ) {
        wp_die( 'Falha de segurança.' );
    }
    if ( session_status() === PHP_SESSION_NONE && ! headers_sent() ) { session_start(); }
    if ( empty( $_SESSION['rmbz_user_id'] ) ) {
        wp_redirect( home_url('/login/') ); exit;
    }
    $project_id = absint( $_POST['project_id'] ?? 0 );
    $telemovel  = sanitize_text_field( $_SESSION['rmbz_user_id'] );
    if ( $project_id <= 0 ) {
        wp_redirect( wp_get_referer() ?: home_url('/minha-conta/') ); exit;
    }

    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';

    // Confirmar que o projecto pertence ao artista
    $proj = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, scenario_details, extra_data FROM {$table_projects}
         WHERE id = %d AND artist_telemovel = %s",
        $project_id, $telemovel
    ) );
    if ( ! $proj ) {
        wp_redirect( home_url('/minha-conta/') ); exit;
    }

    // Confirmar que contrato foi aceite (este handler só funciona pós-aceitação)
    $extra = ! empty( $proj->extra_data ) ? json_decode( $proj->extra_data, true ) : [];
    if ( ! is_array( $extra ) ) $extra = [];
    if ( empty( $extra['contract_accepted'] ) ) {
        $_SESSION['rmbz_withdrawal_notice'] = [ 'error', 'Não é possível decidir items antes de aceitar o contrato.' ];
        wp_redirect( wp_get_referer() ?: home_url('/minha-conta/') ); exit;
    }

    $details = ! empty( $proj->scenario_details ) ? json_decode( $proj->scenario_details, true ) : [];
    if ( ! is_array( $details ) ) {
        wp_redirect( wp_get_referer() ?: home_url('/minha-conta/') ); exit;
    }

    $decisions = isset( $_POST['item_assumes'] ) && is_array( $_POST['item_assumes'] )
        ? $_POST['item_assumes']
        : [];

    $updated_count = 0;
    foreach ( $details as $idx => &$item ) {
        $mp       = isset( $item['must_pay'] ) ? (int) $item['must_pay'] : 1;
        $decided  = isset( $item['decided'] )  ? (int) $item['decided']  : 1;
        // Só aceitar decisão para items NÃO decididos E negociáveis
        if ( $mp === 0 && $decided === 0 && isset( $decisions[ $idx ] ) ) {
            $item['artist_assumes'] = ( (int) $decisions[ $idx ] === 1 ) ? 1 : 0;
            $item['decided'] = 1;
            $updated_count++;
        }
    }
    unset( $item );

    if ( $updated_count > 0 ) {
        $wpdb->update(
            $table_projects,
            [ 'scenario_details' => wp_json_encode( $details ) ],
            [ 'id' => $project_id ]
        );
        $_SESSION['rmbz_withdrawal_notice'] = [ 'success', sprintf( '%d item(s) confirmados com sucesso.', $updated_count ) ];
    } else {
        $_SESSION['rmbz_withdrawal_notice'] = [ 'error', 'Nenhum item foi alterado.' ];
    }

    wp_redirect( wp_get_referer() ?: home_url('/minha-conta/') ); exit;
}
add_action( 'admin_post_onemz_decide_pending_items', 'onemz_decide_pending_items_action' );
add_action( 'admin_post_nopriv_onemz_decide_pending_items', 'onemz_decide_pending_items_action' );

/**
 * ==========================================================================
 * SISTEMA DE CONTRATOS - AÇÕES DA ADMINISTRAÇÃO (UPLOAD E E-MAIL)
 * ==========================================================================
 */
function rmbz_admin_upload_contract() {
    if ( ! current_user_can('manage_options') ) wp_die('Acesso negado.');
    // [SEC-FH3] Adicionado nonce — antes era CSRF-vulnerable: outro site
    // podia, num admin logado, forjar upload de contratos arbitrários.
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'rmbz_admin_upload_contract_nonce') ) {
        wp_die('Falha de segurança (nonce).');
    }
    $project_id = isset($_POST['project_id']) ? intval($_POST['project_id']) : 0;
    
    if ( !empty($_FILES['contract_file']['name']) ) {
        global $wpdb;
        $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
        $table_wallets = $wpdb->prefix . 'rmbz_wallets';
        
        $project = $wpdb->get_row($wpdb->prepare("SELECT artist_telemovel, project_title, extra_data FROM {$table_projects} WHERE id = %d", $project_id));
        
        if ($project) {
            $extra = !empty($project->extra_data) ? json_decode($project->extra_data, true) : [];
            
            // Verifica se é uma retificação (o artista tinha recusado antes)
            $is_retification = isset($extra['contract_rejected']) && $extra['contract_rejected'] === true;
            
            // DESTRUIR O FICHEIRO ANTIGO DO SERVIDOR PARA POUPAR ESPAÇO
            if (!empty($extra['contract_url']) && function_exists('rmbz_destruir_ficheiro_fisico')) {
                rmbz_destruir_ficheiro_fisico($extra['contract_url']);
            }
            
            $url = rmbz_handle_proof_upload('contract_file');
            if ( $url ) {
                // [1.5.399] Fluxo partilhado com o gerador de contrato em PDF.
                $msg_success = rmbz_project_contract_attach_url( $project_id, $url );
                wp_redirect( add_query_arg('msg', urlencode($msg_success), wp_get_referer()) );
                exit;
            }
        }
    }
    wp_die('Erro de Servidor: Falha ao carregar o ficheiro PDF/Imagem.');
}
add_action('admin_post_rmbz_admin_upload_contract', 'rmbz_admin_upload_contract');

/**
 * [1.5.399] Anexa um contrato (URL já gravado) ao projeto e notifica o artista
 * (email + sininho). Extraído de rmbz_admin_upload_contract para ser usado
 * também pelo GERADOR de contrato em PDF (contract-pdf.php).
 *
 * @return string mensagem de sucesso para o admin.
 */
function rmbz_project_contract_attach_url( $project_id, $url ) {
    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $table_wallets  = $wpdb->prefix . 'rmbz_wallets';

    $project = $wpdb->get_row($wpdb->prepare("SELECT artist_telemovel, project_title, extra_data FROM {$table_projects} WHERE id = %d", (int) $project_id));
    if ( ! $project ) return 'Projeto não encontrado.';

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

    // Verifica se é uma retificação (o artista tinha recusado antes)
    $is_retification = isset($extra['contract_rejected']) && $extra['contract_rejected'] === true;

    $extra['contract_url'] = $url;
    $extra['contract_accepted'] = false;
    $extra['contract_rejected'] = false; // Limpa a recusa antiga

    // Limpa as assinaturas e KYC antigos para forçar o artista a assinar o novo
    unset($extra['contract_accepted_date']);
    unset($extra['contract_rejected_reason']);
    unset($extra['contract_real_name']);
    unset($extra['contract_kyc_photo']);

    $wpdb->update($table_projects, ['extra_data' => wp_json_encode($extra)], ['id' => (int) $project_id]);

    // ====================================================================
    // LÓGICA DE ENVIO DE E-MAIL E NOTIFICAÇÃO (SININHO)
    // ====================================================================
    $artist = $wpdb->get_row($wpdb->prepare("SELECT user_email, user_nome FROM {$table_wallets} WHERE user_telemovel = %s", $project->artist_telemovel));

    // Só envia se o artista tiver um e-mail real configurado
    if ($artist && !empty($artist->user_email) && strpos($artist->user_email, '@1mz.local') === false) {
        $artist_name = $artist->user_nome;
        $project_title = $project->project_title;
        $login_url = home_url('/minha-conta/');

        if ($is_retification) {
            $subject = "🔄 Contrato Retificado - " . $project_title;
            $title_msg = "O seu contrato foi retificado!";
            $body_msg = "A administração da 1MZ leu o seu motivo de recusa e enviou um <strong>novo contrato atualizado</strong> para a produção do videoclipe <em>{$project_title}</em>.";
        } else {
            $subject = "📄 Novo Contrato de Produção - " . $project_title;
            $title_msg = "Contrato Disponível para Assinatura";
            $body_msg = "A administração da 1MZ enviou o contrato oficial para a produção do seu videoclipe <em>{$project_title}</em>.";
        }

        $body = "<div style='font-family: Arial; padding: 20px; background: #1a1a1a; color: #fff; border-radius: 8px; border-left: 4px solid #f0b90b;'>
                    <h2 style='color: #f0b90b; margin-top:0;'>{$title_msg}</h2>
                    <p>Olá, <strong>{$artist_name}</strong>!</p>
                    <p>{$body_msg}</p>
                    <p>Para que possamos avançar e desbloquear o botão de pagamento, precisamos que descarregue o documento, leia os termos e <strong>valide a sua identidade enviando a foto com o seu BI</strong>.</p>
                    <div style='margin: 30px 0;'>
                        <a href='{$login_url}' style='background: #f0b90b; color: #000; padding: 12px 25px; text-decoration: none; font-weight: bold; border-radius: 6px; text-transform: uppercase;'>Aceder e Assinar Contrato</a>
                    </div>
                    <p style='font-size: 12px; color: #aaa;'>Se tiver dúvidas, pode usar o chat do projeto na plataforma.</p>
                 </div>";

        if (function_exists('rmbz_build_html_email')) {
            $tpl = get_option('rmbz_email_templates');
            $sender_name = !empty($tpl['sender_name']) ? $tpl['sender_name'] : get_bloginfo('name');
            $sender_email = is_email($tpl['sender_email'] ?? '') ? $tpl['sender_email'] : get_option('admin_email');

            $html_body = rmbz_build_html_email($body, $sender_name);
            $headers = ['Content-Type: text/html; charset=UTF-8', 'From: ' . $sender_name . ' <' . $sender_email . '>'];
            wp_mail($artist->user_email, $subject, $html_body, $headers);
        } else {
            $headers = ['Content-Type: text/html; charset=UTF-8'];
            wp_mail($artist->user_email, $subject, $body, $headers);
        }

        // Guarda o log para o utilizador ver também no "Sininho 🔔" da plataforma.
        // [1.5.400] Grava só o CONTEÚDO ($body) — nunca o email completo com o
        // tema (faixa dourada/™), que aparecia cortado no modal do sino.
        $wpdb->insert($wpdb->prefix . 'rmbz_email_logs', [
            'recipient_email' => $artist->user_email,
            'subject' => $subject,
            'body' => $body,
            'sent_date' => current_time('mysql', 1),
            'is_read' => 0,
            'is_cleared' => 0
        ], ['%s', '%s', '%s', '%s', '%d', '%d']);
    }

    // [1.5.399] Push + sino do APP (o email/sino do site já foi acima).
    if ( function_exists('rmbz_notify_user') ) {
        rmbz_notify_user(
            (string) $project->artist_telemovel,
            $is_retification ? '🔄 Contrato retificado' : '📄 Contrato disponível',
            sprintf('O contrato do videoclipe "%s" está disponível na tua conta — lê, valida a identidade e assina para a produção avançar.', (string) $project->project_title),
            'warning'
        );
    }

    return $is_retification
        ? 'Contrato retificado e e-mail enviado ao artista para assinar!'
        : 'Contrato submetido! O artista recebeu um e-mail para assinar e enviar o BI.';
}

function rmbz_admin_force_reject_project() {
    if ( ! current_user_can('manage_options') ) wp_die('Acesso negado.');
    // [SEC-FH4] Adicionado nonce — antes era CSRF-vulnerable.
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'rmbz_admin_force_reject_nonce') ) {
        wp_die('Falha de segurança (nonce).');
    }
    $project_id = isset($_POST['project_id']) ? intval($_POST['project_id']) : 0;
    $reason = isset($_POST['admin_rejection_reason']) ? sanitize_text_field( wp_unslash($_POST['admin_rejection_reason']) ) : '';
    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $project = $wpdb->get_row($wpdb->prepare("SELECT extra_data FROM {$table_projects} WHERE id = %d", $project_id));
    if ($project) {
        $extra = !empty($project->extra_data) ? json_decode($project->extra_data, true) : [];
        $extra['admin_rejection_reason'] = $reason;
        $extra['rejected_at'] = current_time('mysql'); // Inicia a contagem dos 30 dias para apagar
        
        $wpdb->update($table_projects, ['production_status' => 'rejected', 'extra_data' => wp_json_encode($extra)], ['id' => $project_id]);
        wp_redirect( add_query_arg('msg', urlencode('Projeto bloqueado! O artista não concordou e a conta foi travada. Será eliminado em 30 dias.'), wp_get_referer()) );
        exit;
    }
}
add_action('admin_post_rmbz_admin_force_reject_project', 'rmbz_admin_force_reject_project');

function onemz_artist_choose_budget() {
    if ( ! isset( $_POST['project_id'], $_POST['_wpnonce'] ) ) wp_die('Erro.');
    if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'onemz_choose_budget_nonce' ) ) wp_die('Segurança.');

    // [SEC-FH1] Antes faltava: auth + ownership. O nonce sozinho não impede
    // que um artista A escolha orçamento de um projecto do artista B (basta
    // ler o HTML do próprio dashboard para conseguir um nonce válido).
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');

    $project_id = absint($_POST['project_id']);
    $chosen_loc = sanitize_text_field( wp_unslash($_POST['chosen_location'] ?? '') );
    $telemovel  = rmbz_get_current_user_telemovel();

    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_artist_projects';

    // [SEC-FH1] Ownership: só dono do projecto pode escolher orçamento.
    $project = $wpdb->get_row( $wpdb->prepare(
        "SELECT extra_data FROM {$table} WHERE id = %d AND artist_telemovel = %s",
        $project_id, $telemovel
    ) );

    if ($project) {
        $extra = json_decode($project->extra_data, true);
        if ( ! is_array($extra) ) $extra = [];
        if (isset($extra['proposed_budgets'][$chosen_loc])) {
            $budget_data = $extra['proposed_budgets'][$chosen_loc];
            
            // Define o orçamento oficial
            $extra['budget_accepted_location'] = $chosen_loc;
            unset($extra['proposed_budgets']); // Descarta as outras opções
            unset( $extra['location_choice_set_at'], $extra['location_cancel_warned'] );
            
            $wpdb->update($table, [
                'scenario_details' => wp_json_encode($budget_data['items']),
                'scenario_cost'    => $budget_data['total'],
                'extra_data'       => wp_json_encode($extra)
            ], ['id' => $project_id]);
            
            if ( session_status() === PHP_SESSION_NONE && ! headers_sent() ) { session_start(); }
            $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Orçamento de '. esc_html($chosen_loc) .' selecionado com sucesso! Já pode avançar.'];
        }
    }
    wp_redirect(wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/')); exit;
}
add_action('admin_post_onemz_artist_choose_budget', 'onemz_artist_choose_budget');
// [SEC-FH1] nopriv mantido (sistema usa sessão custom), mas auth já é
// validada acima antes de qualquer escrita.
add_action('admin_post_nopriv_onemz_artist_choose_budget', 'onemz_artist_choose_budget');
/* ============================================================================
 * [1.6.118.64] Datas de gravação — handlers do site (paridade com a API).
 * ============================================================================ */

/**
 * Artista confirma as datas de gravação definidas pelo admin.
 */
function onemz_confirm_filming_dates_action() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'onemz_filming_nonce') ) {
        wp_die('Falha de segurança (nonce).');
    }
    $project_id = isset($_POST['project_id']) ? intval($_POST['project_id']) : 0;
    $telemovel = rmbz_get_current_user_telemovel();
    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $project = $wpdb->get_row($wpdb->prepare("SELECT extra_data, artist_feedback FROM {$table_projects} WHERE id = %d AND artist_telemovel = %s", $project_id, $telemovel));
    if ($project) {
        $extra = !empty($project->extra_data) ? json_decode($project->extra_data, true) : [];
        if ( ! is_array($extra) ) $extra = [];
        if ( ! empty($extra['filming_start']) || ! empty($extra['filming_end']) ) {
            $was_confirmed = ! empty($extra['filming_confirmed_by_artist']);
            $extra['filming_confirmed_by_artist'] = true;
            unset($extra['filming_proposed_by_artist']);
            $wpdb->update($table_projects, ['extra_data' => wp_json_encode($extra)], ['id' => $project_id]);

            if ( ! $was_confirmed ) {
                // Registar uma única confirmação como evento do sistema.
                $ts = current_time('d/m/Y H:i');
                $entry = "[$ts] <strong>Sistema:</strong> Datas de gravação confirmadas pelo artista.";
                $prev = (string) ($project->artist_feedback ?? '');
                $new_feedback = $prev === '' ? $entry : $prev . "\n\n" . $entry;
                $wpdb->update($table_projects, ['artist_feedback' => $new_feedback], ['id' => $project_id]);
            }

            if ( session_status() === PHP_SESSION_NONE && ! headers_sent() ) { session_start(); }
            $_SESSION['rmbz_withdrawal_notice'] = ['success', 'Datas de gravação confirmadas. A equipa foi notificada.'];
        }
    }
    wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
}
add_action('admin_post_onemz_confirm_filming_dates', 'onemz_confirm_filming_dates_action');
add_action('admin_post_nopriv_onemz_confirm_filming_dates', 'onemz_confirm_filming_dates_action');

/**
 * Artista propõe datas alternativas de gravação.
 */
function onemz_propose_filming_dates_action() {
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) wp_die('Acesso negado.');
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce($_POST['_wpnonce'], 'onemz_filming_nonce') ) {
        wp_die('Falha de segurança (nonce).');
    }
    $project_id = isset($_POST['project_id']) ? intval($_POST['project_id']) : 0;
    $telemovel  = rmbz_get_current_user_telemovel();

    $start_raw = isset($_POST['propose_start']) ? sanitize_text_field($_POST['propose_start']) : '';
    $end_raw   = isset($_POST['propose_end'])   ? sanitize_text_field($_POST['propose_end'])   : '';
    $start = ( $start_raw !== '' && strtotime($start_raw) ) ? date('Y-m-d', strtotime($start_raw)) : '';
    $end   = ( $end_raw   !== '' && strtotime($end_raw) )   ? date('Y-m-d', strtotime($end_raw))   : '';

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

    if ( $start === '' || $end === '' ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Indica a data de início e de fim.'];
        wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
    }
    if ( strtotime($end) < strtotime($start) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'A data de fim não pode ser anterior à de início.'];
        wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
    }
    if ( strtotime($start) < strtotime(date('Y-m-d')) ) {
        $_SESSION['rmbz_withdrawal_notice'] = ['error', 'Não podes propor uma data no passado.'];
        wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
    }

    global $wpdb;
    $table_projects = $wpdb->prefix . 'rmbz_artist_projects';
    $project = $wpdb->get_row($wpdb->prepare("SELECT extra_data, artist_feedback FROM {$table_projects} WHERE id = %d AND artist_telemovel = %s", $project_id, $telemovel));
    if ($project) {
        $extra = !empty($project->extra_data) ? json_decode($project->extra_data, true) : [];
        if ( ! is_array($extra) ) $extra = [];
        $extra['filming_proposed_by_artist'] = [
            'start' => $start,
            'end'   => $end,
            'at'    => current_time('mysql', 1),
        ];
        $extra['filming_confirmed_by_artist'] = false;
        $wpdb->update($table_projects, ['extra_data' => wp_json_encode($extra)], ['id' => $project_id]);

        // Registar a proposta como evento do sistema no histórico.
        $ts = current_time('d/m/Y H:i');
        $ds = date_i18n('d/m/Y', strtotime($start));
        $de = date_i18n('d/m/Y', strtotime($end));
        $entry = "[$ts] <strong>Sistema:</strong> Nova proposta de gravação: {$ds} a {$de}.";
        $prev = (string) ($project->artist_feedback ?? '');
        $new_feedback = $prev === '' ? $entry : $prev . "\n\n" . $entry;
        $wpdb->update($table_projects, ['artist_feedback' => $new_feedback], ['id' => $project_id]);

        $_SESSION['rmbz_withdrawal_notice'] = ['success', 'A tua proposta de datas foi enviada. Aguarda resposta da equipa.'];
    }
    wp_redirect( wp_get_referer() ? wp_get_referer() : home_url('/minha-conta/') ); exit;
}
add_action('admin_post_onemz_propose_filming_dates', 'onemz_propose_filming_dates_action');
add_action('admin_post_nopriv_onemz_propose_filming_dates', 'onemz_propose_filming_dates_action');
