<?php

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

class IMZ_Mpesa_API {

    private $api_key;
    private $public_key;
    private $service_provider_code;
    private $api_base_url;

    public function __construct() {
        $this->api_key = get_option('imz_mpesa_api_key');
        $this->public_key = get_option('imz_mpesa_public_key');
        $this->service_provider_code = get_option('imz_mpesa_till_number');
        
        $mode = get_option('imz_mpesa_api_mode', 'sandbox');
        if ($mode === 'production') {
            $this->api_base_url = 'https://api.vm.co.mz:18352/ipg/v1x/';
        } else {
            $this->api_base_url = 'https://api.sandbox.vm.co.mz:18352/ipg/v1x/';
        }
    }

    /**
     * Encripta a API Key usando a Public Key para gerar o Bearer Token.
     */
    private function get_encrypted_bearer_token() {
        if (empty($this->public_key) || empty($this->api_key)) {
            return null;
        }

        // Formata a chave pública para o formato correto que a função de encriptação espera
        $key_string = "-----BEGIN PUBLIC KEY-----\n" .
                      chunk_split(
                          preg_replace('/(-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\r|\n)/', '', $this->public_key),
                          64, 
                          "\n"
                      ) .
                      "-----END PUBLIC KEY-----\n";
        
        $public_key_resource = openssl_get_publickey($key_string);
        if (!$public_key_resource) {
            return null; // Chave pública inválida
        }

        if (!openssl_public_encrypt($this->api_key, $encrypted_data, $public_key_resource, OPENSSL_PKCS1_PADDING)) {
            return null; // Falha na encriptação
        }

        return base64_encode($encrypted_data);
    }

    /**
     * Obtém o token de acesso para autenticar os pedidos.
     */
    public function get_access_token() {
        $token = get_transient('mpesa_access_token');
        if ($token && !is_array($token)) return $token;

        $encrypted_token = $this->get_encrypted_bearer_token();
        if (!$encrypted_token) {
            return ['error' => 'Falha ao gerar o token de segurança. Verifique se a sua Public Key está correta e completa.'];
        }

        $response = wp_remote_post($this->api_base_url . 'token/', [
            'headers' => [ 'Authorization' => 'Bearer ' . $encrypted_token, 'Origin' => get_site_url() ]
        ]);

        if (is_wp_error($response)) {
            return ['error' => 'Erro de comunicação ao obter token: ' . $response->get_error_message()];
        }

        $body = json_decode(wp_remote_retrieve_body($response), true);

        if (isset($body['output_AccessToken'])) {
            $token = $body['output_AccessToken'];
            $expires_in = isset($body['output_ExpiresIn']) ? intval($body['output_ExpiresIn']) - 60 : 3540;
            set_transient('mpesa_access_token', $token, $expires_in);
            return $token;
        }
        
        $error_desc = $body['output_ResponseDesc'] ?? 'Não foi possível obter o token de acesso. Verifique as suas credenciais de API.';
        return ['error' => $error_desc];
    }

    /**
     * Inicia um pagamento C2B (Customer to Business).
     */
    public function initiate_c2b_payment($amount, $customer_msisdn, $transaction_ref, $third_party_ref) {
        $auth_result = $this->get_access_token();
        
        if (is_array($auth_result) && isset($auth_result['error'])) return $auth_result;
        
        $access_token = $auth_result;

        $request_body = [
            'input_TransactionReference' => $transaction_ref,
            'input_CustomerMSISDN' => $customer_msisdn,
            'input_Amount' => $amount,
            'input_ThirdPartyReference' => $third_party_ref,
            'input_ServiceProviderCode' => $this->service_provider_code,
        ];

        $headers = [
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . $access_token,
            'Origin' => get_site_url()
        ];

        $response = wp_remote_post($this->api_base_url . 'c2bPayment/singleStage/', [
            'headers' => $headers,
            'body' => json_encode($request_body),
            'timeout' => 60,
        ]);

        if (is_wp_error($response)) {
            return ['error' => 'Erro de comunicação com o servidor M-Pesa: ' . $response->get_error_message()];
        }

        return json_decode(wp_remote_retrieve_body($response), true);
    }
}


// --- LÓGICA DO CALLBACK (OUVINTE) ---

/**
 * Valida o endereço IP da Vodacom.
 * @param WP_REST_Request $request
 * @return bool
 */
function imz_mpesa_permission_callback(WP_REST_Request $request) {
    // Lista de IPs de produção da Vodacom. Adicione mais se necessário.
    $vodacom_ips = ['196.11.240.0/24']; 
    $request_ip = $request->get_ip();

    foreach ($vodacom_ips as $ip_range) {
        if (ip_in_range($request_ip, $ip_range)) {
            return true;
        }
    }
    
    // Em modo sandbox, só aceita o IP de teste configurado nas definições.
    // Se o campo estiver vazio, recusa tudo (nunca aceitar callbacks de qualquer origem).
    $api_mode = get_option('imz_mpesa_api_mode', 'sandbox');
    if ($api_mode === 'sandbox') {
        $test_ip = trim((string) get_option('imz_mpesa_test_ip', ''));
        if (!empty($test_ip) && $request_ip === $test_ip) {
            return true;
        }
        error_log('Callback M-Pesa (sandbox) recusado para o IP: ' . $request_ip . (empty($test_ip) ? ' (nenhum IP de teste configurado)' : ''));
        return false;
    }

    // Log de tentativa de acesso negado
    error_log('Acesso negado ao callback M-Pesa do IP: ' . $request_ip);
    return false;
}

// Função auxiliar para verificar se um IP está num range (formato CIDR)
function ip_in_range($ip, $range) {
    if (strpos($range, '/') === false) {
        $range .= '/32';
    }
    list($subnet, $bits) = explode('/', $range);
    $ip = ip2long($ip);
    $subnet = ip2long($subnet);
    $mask = -1 << (32 - $bits);
    $subnet &= $mask;
    return ($ip & $mask) == $subnet;
}


function imz_register_mpesa_callback_endpoint() {
    register_rest_route('1musicmoz/v1', '/mpesa-callback', [
        'methods' => 'POST',
        'callback' => 'imz_handle_mpesa_callback_request',
        'permission_callback' => 'imz_mpesa_permission_callback'
    ]);
}
add_action('rest_api_init', 'imz_register_mpesa_callback_endpoint');


function imz_handle_mpesa_callback_request(WP_REST_Request $request) {
    $body = $request->get_json_params();
    error_log('M-Pesa Callback Recebido: ' . print_r($body, true));

    if (isset($body['input_ResultCode']) && $body['input_ResultCode'] === '0') {
        $third_party_ref = $body['input_ThirdPartyReference'];
        $amount = $body['input_Amount'];
        $msisdn = $body['input_CustomerMSISDN'];
        if (strpos($third_party_ref, 'AD') === 0) {
            // Pagamento de anúncio — redundância do fluxo síncrono (imz_ad_mark_paid é idempotente)
            $parts = explode('_', substr($third_party_ref, 2));
            $ad_id = absint($parts[0] ?? 0);
            if ($ad_id && function_exists('imz_ad_mark_paid')) {
                imz_ad_mark_paid($ad_id, sanitize_text_field((string) $msisdn), $amount, $third_party_ref, 'M-Pesa API (callback)');
            }
        } elseif (strpos($third_party_ref, 'BOOST') === 0) {
            $parts = explode('_', str_replace('BOOST', '', $third_party_ref));
            $post_id = absint($parts[0]);
            if ($post_id > 0) {
                remove_filter('the_title', 'imz_add_verified_badge_to_title', 10, 2);
                $post_title = get_the_title($post_id);
                add_filter('the_title', 'imz_add_verified_badge_to_title', 10, 2);
                
                wp_insert_post([
                    'post_type' => 'impulsionamento',
                    'post_title' => 'Impulsionamento API - ' . $post_title,
                    'post_status' => 'publish',
                    'meta_input' => [
                        'post_id_original' => $post_id, 'valor' => $amount, 'nome' => 'Pagamento API',
                        'comprovativo_url' => '', 'comprovativo_id'  => '', 'metodo_pagamento' => 'M-Pesa API',
                        'telefone_pagador' => $msisdn, 'status' => 'aprovado',
                        '_boost_duracao_dias' => 1,
                        '_boost_data_inicio' => current_time('Y-m-d H:i:s'),
                        '_boost_data_fim' => date('Y-m-d H:i:s', strtotime('+1 day')),
                    ]
                ]);
            }
        }
    }
    return new WP_REST_Response('Callback recebido.', 200);
}