<?php
// includes/distribution/distribution-financial.php

if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * Transfere fundos dos Royalties (USD) para a Carteira Principal (MT).
 * Esta operação é ATÓMICA: ou acontece tudo, ou não acontece nada (Rollback).
 * * @param string $telemovel O ID do artista.
 * @param float $amount_usd O valor em Dólares a retirar.
 * @return array ['success' => bool, 'message' => string]
 */
function rmbz_secure_transfer_usd_to_mt( $telemovel, $amount_usd ) {
    global $wpdb;
    
    // 1. Validação Básica
    if ( $amount_usd <= 0 ) {
        return ['success' => false, 'message' => 'Valor inválido para retirada.'];
    }

    $table_stats  = $wpdb->prefix . 'rmbz_distro_stats';
    $table_ledger = $wpdb->prefix . 'rmbz_distro_ledger';
    $table_wallets = $wpdb->prefix . 'rmbz_wallets';
    $table_wallet_trans = $wpdb->prefix . 'rmbz_wallet_transactions';

    // 2. INICIAR TRANSAÇÃO (Bloqueia a base de dados para evitar erros concorrentes)
    $wpdb->query( 'START TRANSACTION' );

    try {
        // ------------------------------------------------------------------
        // FASE 1: DEBITAR OS DÓLARES (USD)
        // ------------------------------------------------------------------

        // 3. Verificar Saldo Atual (USD) com bloqueio de leitura (FOR UPDATE)
        // Isso impede "Race Conditions" (clicar 2 vezes rápido).
        $current_stats = $wpdb->get_row( $wpdb->prepare(
            "SELECT total_earnings FROM $table_stats WHERE artist_telemovel = %s FOR UPDATE", 
            $telemovel
        ) );

        $current_balance_usd = $current_stats ? (float)$current_stats->total_earnings : 0.00;

        // Verifica se tem saldo suficiente
        // Usamos round para evitar erros de ponto flutuante (0.0000001)
        if ( round($current_balance_usd, 4) < round($amount_usd, 4) ) {
            throw new Exception( 'Saldo insuficiente em Dólares.' );
        }

        // 4. Calcular novo saldo USD
        $new_balance_usd = $current_balance_usd - $amount_usd;
        
        // 5. Atualizar Tabela de Stats
        // [BUGFIX 1.5.17] Antes usava 'updated_at' que só existe se o
        // distribution-schema-patch.php tiver corrido. O schema original
        // (functions-setup.php) tem apenas 'last_updated'. Usar a coluna
        // garantida por ambos os schemas evita falhas em instalações
        // parcialmente migradas.
        $update_usd = $wpdb->update(
            $table_stats,
            ['total_earnings' => $new_balance_usd, 'last_updated' => current_time('mysql')],
            ['artist_telemovel' => $telemovel],
            ['%f', '%s'],
            ['%s']
        );

        if ( $update_usd === false ) {
            error_log( '[1MZ] rmbz_secure_transfer_usd_to_mt update stats failed: ' . $wpdb->last_error );
            throw new Exception( 'Erro técnico ao atualizar saldo de distribuição.' );
        }

        // 6. Registar no Ledger (Extrato USD)
        $log_usd = $wpdb->insert(
            $table_ledger,
            [
                'artist_telemovel' => $telemovel,
                'amount'           => -$amount_usd, // Negativo (Saída)
                'currency'         => 'USD',
                'type'             => 'withdrawal_to_wallet',
                'description'      => 'Transferência para Carteira Principal (Conversão)',
                'balance_after'    => $new_balance_usd,
                'reference_id'     => 'CONV_' . date('YmdHis') . '_' . rand(100,999),
                'created_at'       => current_time('mysql')
            ],
            ['%s', '%f', '%s', '%s', '%s', '%f', '%s', '%s']
        );

        if ( $log_usd === false ) {
            error_log( '[1MZ] rmbz_secure_transfer_usd_to_mt ledger insert failed: ' . $wpdb->last_error );
            throw new Exception( 'Erro ao registar log de distribuição.' );
        }
        $ledger_id = $wpdb->insert_id; // Guardamos este ID para ligar as duas transações

        // ------------------------------------------------------------------
        // FASE 2: CREDITAR OS METICAIS (MT)
        // ------------------------------------------------------------------

        // 7. Converter Moeda
        // [BUGFIX 1.5.10] Unificado no helper rmbz_get_exchange_rate().
        $rate = function_exists('rmbz_get_exchange_rate')
            ? rmbz_get_exchange_rate()
            : max( 63.50, (float) get_option('rmbz_exchange_rate', 63.50) );
        
        $amount_mt = $amount_usd * $rate;

        // 8. Buscar Saldo Atual da Carteira (MT)
        $wallet = $wpdb->get_row( $wpdb->prepare("SELECT balance FROM $table_wallets WHERE user_telemovel = %s", $telemovel) );
        
        // Se a carteira não existir, criamos (caso raro, mas possível)
        if ( ! $wallet ) {
            // Lógica simplificada de criação (o ideal é já existir)
            $wpdb->insert($table_wallets, ['user_telemovel' => $telemovel, 'balance' => 0.00, 'user_nome' => 'Artista', 'user_email' => $telemovel.'@temp.com', 'user_pin' => '...']);
            $current_balance_mt = 0.00;
        } else {
            $current_balance_mt = (float)$wallet->balance;
        }

        $new_wallet_balance = $current_balance_mt + $amount_mt;

        // 9. Atualizar Carteira (MT)
        $update_mt = $wpdb->update(
            $table_wallets,
            ['balance' => $new_wallet_balance],
            ['user_telemovel' => $telemovel],
            ['%f'],
            ['%s']
        );

        if ( $update_mt === false ) {
            error_log( '[1MZ] rmbz_secure_transfer_usd_to_mt update wallet failed: ' . $wpdb->last_error );
            throw new Exception( 'Erro ao creditar a carteira principal.' );
        }

        // 10. Registar no Histórico da Carteira (MT)
        // [BUGFIX 1.5.17] Antes usava 'rifa_id' que NÃO existe no schema de
        // rmbz_wallet_transactions. O insert falhava sempre, o throw disparava
        // e o rollback cancelava toda a transferência. Resultado: a conversão
        // USD→MT nunca funcionou na prática. O utilizador via "Erro ao
        // registar histórico da carteira. Transação cancelada".
        // O schema tem: user_telemovel, amount, type, reference_id, project_id,
        // details, is_unlocked, unlock_date, transaction_date. Usamos
        // reference_id para linkar ao ledger USD (propósito semântico certo).
        $log_mt = $wpdb->insert(
            $table_wallet_trans,
            [
                'user_telemovel'   => $telemovel,
                'reference_id'     => $ledger_id, // Link cruzado para o ledger USD
                'amount'           => $amount_mt,
                'type'             => 'distro_payout',
                'details'          => sprintf(
                    'Recebido de Royalties ($%s USD × %s MT)',
                    number_format($amount_usd, 2),
                    number_format($rate, 2)
                ),
                'transaction_date' => current_time('mysql', 1),
                'is_unlocked'      => 1,
            ],
            ['%s', '%d', '%f', '%s', '%s', '%s', '%d']
        );

        if ( $log_mt === false ) {
            // Se o insert falhou, registar o erro do MySQL no log para diagnose
            error_log( '[1MZ] rmbz_secure_transfer_usd_to_mt insert wallet_trans failed: ' . $wpdb->last_error );
            throw new Exception( 'Erro ao registar histórico da carteira.' );
        }

        // ------------------------------------------------------------------
        // FASE 3: SUCESSO
        // ------------------------------------------------------------------

        // 11. Confirmar tudo (COMMIT)
        $wpdb->query( 'COMMIT' );
        
        return [
            'success' => true,
            'message' => 'Sucesso! Convertidos ' . number_format($amount_usd, 2) . ' USD em ' . number_format($amount_mt, 2) . ' MT.'
        ];

    } catch ( Exception $e ) {
        // 12. FALHA CRÍTICA: DESFAZER TUDO (ROLLBACK)
        // Se algo falhou no meio do caminho, revertemos a base de dados ao estado inicial.
        // O dinheiro não sai do USD e não entra no MT. Ninguém perde nada.
        $wpdb->query( 'ROLLBACK' );
        
        return [
            'success' => false,
            'message' => 'Transação cancelada: ' . $e->getMessage()
        ];
    }
}


/**
 * [FEAT 1.5.35] Reverte uma transferência USD→MT.
 *
 * Usado quando um pedido de levantamento de Royalties é rejeitado pelo
 * admin: em vez de creditar MT na carteira (errado, porque o dinheiro veio
 * dos USD), tiramos o MT da carteira e devolvemos os USD aos royalties,
 * usando o MESMO câmbio que foi gravado na altura do pedido. Isto garante
 * que o utilizador fica exactamente como estava antes do pedido — sem
 * perder nem ganhar dinheiro por flutuações cambiais.
 *
 * Atómica via transação SQL: ou tudo acontece, ou nada acontece.
 *
 * NOTA: este helper NÃO debita a carteira. Espera que o caller já tenha
 * feito o débito MT (que neste caso já está contabilizado no histórico do
 * pedido original). Esta função só credita os USD de volta nos royalties.
 *
 * @param string $telemovel
 * @param float  $amount_mt        Valor em MT que foi originalmente debitado
 * @param float  $exchange_rate    Câmbio que foi usado na altura do pedido
 * @param int    $withdrawal_id    ID do pedido (para o ledger)
 * @return array ['success' => bool, 'message' => string, 'amount_usd' => float]
 */
function rmbz_secure_revert_mt_to_usd( $telemovel, $amount_mt, $exchange_rate, $withdrawal_id ) {
    global $wpdb;

    // Validações
    if ( $amount_mt <= 0 ) {
        return ['success' => false, 'message' => 'Valor MT inválido.'];
    }
    if ( $exchange_rate <= 0 ) {
        return ['success' => false, 'message' => 'Câmbio inválido — pedido pode ser de versão antiga sem câmbio gravado.'];
    }

    $table_stats     = $wpdb->prefix . 'rmbz_distro_stats';
    $table_ledger    = $wpdb->prefix . 'rmbz_distro_ledger';
    $table_requests  = $wpdb->prefix . 'rmbz_withdrawal_requests';

    // [DS 1.5.106] Buscar o pedido original para enriquecer a linha de
    // reembolso. Sem isto, o admin via uma entrada misteriosa no ledger
    // sem rastro da origem ("o dinheiro voltou de onde?").
    $original_request = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, request_date, payment_method, payment_details, source
         FROM $table_requests WHERE id = %d",
        $withdrawal_id
    ) );

    // Período derivado do pedido (YYYY-MM). Se não encontrarmos o pedido
    // (caso muito raro), usamos o mês corrente como fallback.
    $period = '';
    $method = 'desconhecido';
    $dest   = '?';
    $req_dt = '?';
    if ( $original_request ) {
        $period = substr( (string) $original_request->request_date, 0, 7 );
        $method = (string) $original_request->payment_method;
        $dest   = (string) $original_request->payment_details;
        $req_dt = date_i18n('d/m/Y H:i', strtotime((string) $original_request->request_date));
    }
    if ( empty($period) ) $period = current_time('Y-m');

    // Calcular o USD a devolver usando o câmbio original
    $amount_usd = round( $amount_mt / $exchange_rate, 4 );

    $wpdb->query( 'START TRANSACTION' );

    try {
        // Buscar saldo actual de royalties (FOR UPDATE para evitar race)
        $current = $wpdb->get_row( $wpdb->prepare(
            "SELECT total_earnings FROM $table_stats WHERE artist_telemovel = %s FOR UPDATE",
            $telemovel
        ) );

        if ( ! $current ) {
            // Não tem linha de stats — criar uma
            $insert_ok = $wpdb->insert(
                $table_stats,
                [
                    'artist_telemovel' => $telemovel,
                    'total_earnings'   => $amount_usd,
                    'last_updated'     => current_time('mysql'),
                ],
                ['%s', '%f', '%s']
            );
            if ( $insert_ok === false ) {
                throw new Exception( 'Falha ao criar linha de royalties: ' . $wpdb->last_error );
            }
            $new_balance_usd = $amount_usd;
        } else {
            $current_balance_usd = (float) $current->total_earnings;
            $new_balance_usd = $current_balance_usd + $amount_usd;

            $update_ok = $wpdb->update(
                $table_stats,
                ['total_earnings' => $new_balance_usd, 'last_updated' => current_time('mysql')],
                ['artist_telemovel' => $telemovel],
                ['%f', '%s'],
                ['%s']
            );
            if ( $update_ok === false ) {
                throw new Exception( 'Falha ao actualizar saldo de royalties: ' . $wpdb->last_error );
            }
        }

        // [DS 1.5.106] Registar no ledger com TODA a informação rastreável.
        // Agora o admin consegue ver onde o dinheiro originou e para onde
        // foi pedido inicialmente, bastando olhar para a linha do extracto.
        $description = sprintf(
            'Reembolso de pedido de levantamento rejeitado — Pedido #%d (%s) · %.2f MT → $%.4f USD ao câmbio %.4f · Método: %s · Destino: %s',
            $withdrawal_id,
            $req_dt,
            $amount_mt,
            $amount_usd,
            $exchange_rate,
            $method,
            $dest
        );

        $log_ok = $wpdb->insert(
            $table_ledger,
            [
                'artist_telemovel'  => $telemovel,
                'amount'            => $amount_usd, // Positivo (entrada)
                'currency'          => 'USD',
                'original_amount'   => $amount_mt,    // Quanto MT voltou
                'original_currency' => 'MZN',         // Era MT
                'exchange_rate'     => $exchange_rate,
                'source_name'       => 'Reembolso de Levantamento Rejeitado',
                'reporting_period'  => $period,       // Mês do pedido original
                'type'              => 'withdrawal_rejected_revert',
                'description'       => $description,
                'balance_after'     => $new_balance_usd,
                'reference_id'      => 'REVERT_WD_' . $withdrawal_id,
                'created_at'        => current_time('mysql'),
            ],
            ['%s','%f','%s','%f','%s','%f','%s','%s','%s','%s','%f','%s','%s']
        );
        if ( $log_ok === false ) {
            throw new Exception( 'Falha ao registar ledger USD: ' . $wpdb->last_error );
        }

        $wpdb->query( 'COMMIT' );

        return [
            'success'    => true,
            'message'    => sprintf( '$%.4f USD devolvidos aos royalties.', $amount_usd ),
            'amount_usd' => $amount_usd,
        ];

    } catch ( Exception $e ) {
        $wpdb->query( 'ROLLBACK' );
        return [
            'success' => false,
            'message' => 'Reversão cancelada: ' . $e->getMessage(),
        ];
    }
}