<?php

namespace App\Http\Controllers;

use App\Models\CodeUser;
use App\Models\SchemaComptable;
use App\Models\Serveur;
use Carbon\Carbon;
use DOMDocument;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use SimpleXMLElement;
use SoapClient;
use SoapFault;

class SoapRequestController extends Controller
{

    public function handleSoapRequest(Request $request)
    {
       // Parse the raw XML content from the request
       $xmlContent = $request->getContent();
        // Log the raw XML request for debugging
        Log::info('Received SOAP Request:', ['xml' => $xmlContent]);

       // Load the XML content using SimpleXMLElement
       $xml = new \SimpleXMLElement($xmlContent);

       // Extract the requestType from the XML structure (adapt based on your actual XML)
       // Adjust the path based on your WSDL structure, this example assumes a path like:
       // /Envelope/Body/GetAccountBalance/AccountBalanceInquiryRequest/mmHeaderInfo/requestType
       $requestType = (string) $xml->xpath('//mmHeaderInfo/requestType')[0];
       // Log the extracted requestType for debugging
       Log::info('Extracted requestType:', ['requestType' => $requestType]);
        //return $requestType;

        try {
            switch ($requestType) {
                case 'GETACCBAL':
                    return $this->getAccountBalance($xml);
                case 'GETMINI':
                    return $this->getMiniStatement($xml);
                case 'W2A':
                    return $this->walletToAccountTransfer($xml);
                case 'A2W':
                    return $this->AccountToWalletTransfer($xml);
                case 'TRANINQ':
                    return $this->transferStatusInquiry($xml);
                default:
                    //return $this->sendError('Unknown request type: ' . $requestType);
                     return $this->sendError("010","","","","Unknown request type: ' . $requestType","",null);
            }
        } catch (\Exception $e) {
            return $this->sendError("010","","","",$e->getMessage(),"",null);

        }
    }

    //GET BALANCE


    private function getAccountBalance($xml)
{
    try {
        // Extract mmHeaderInfo fields
        $mmHeaderInfo = $xml->xpath('//AccountBalanceInquiryRequest/mmHeaderInfo')[0];
        $operatorCode = (string) $mmHeaderInfo->operatorCode;
        $requestId = (string) $mmHeaderInfo->requestId;
        $requestToken = (string) $mmHeaderInfo->requestToken;
        $requestType = (string) $mmHeaderInfo->requestType;
        $affiliateCode = (string) $mmHeaderInfo->affiliateCode;

        // Extract other fields from the request
        $accountNo = (string) $xml->xpath('//AccountBalanceInquiryRequest/accountNo')[0];
        $accountAlias = (string) $xml->xpath('//AccountBalanceInquiryRequest/accountAlias')[0];
        $reason = (string) $xml->xpath('//AccountBalanceInquiryRequest/reason')[0];

        // Generate a unique reference number for tracking purposes
        $referenceNumber = uniqid('ref_', true);

        // Log the initial request in the transaction_statuses table
        DB::table('transaction_statuses')->insert([
            'date' => now(),
            'type' => 'GetAccountBalance',
            'alias' => $accountAlias,
            'currency' => 'XOF',
            'amount' => 0,
            'request_code' => $requestId,
            'response_code' => '', // Initially empty, updated after processing
            'response_message' => 'Pending',
            'reference_number' => $referenceNumber,
            'status' => 1, // 1 for pending
            'created_at' => now(),
            'update_at' => now()
        ]);

        // Retrieve the account balance (simulate errors or fetch actual balance)
        $availableBalance = 0;
        $balanceResult = $this->getBalance($accountAlias);

        if ($balanceResult === "Account not found") {
            $this->updateTransactionStatus($referenceNumber, 'E01', 'Account not found', 2);
            return $this->sendError("E01",$operatorCode,$requestId,$affiliateCode,'Account not found',$referenceNumber,"GetAccountBalanceResponse");
        } elseif ($balanceResult === "Error getting account balance") {
            $this->updateTransactionStatus($referenceNumber, 'E02', 'Error getting account balance', 2);
            return $this->sendError("E02",$operatorCode,$requestId,$affiliateCode,'Error getting account balance',$referenceNumber,"GetAccountBalanceResponse");
        } elseif ($balanceResult === "Database connection failed") {
            $this->updateTransactionStatus($referenceNumber, 'E03', 'Database connection failed', 2);
            return $this->sendError("E03",$operatorCode,$requestId,$affiliateCode,'Database connection failed',$referenceNumber,"GetAccountBalanceResponse");
        } else {
            $availableBalance = $balanceResult;
        }

        // Define currency and build XML success response
        $currency = 'XOF';
        $xmlResponse = <<<XML
        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:b2w="http://b2w.banktowallet.com/b2w">
            <soapenv:Header/>
            <soapenv:Body>
                <b2w:GetAccountBalanceResponse>
                <return>
                    <mmHeaderInfo>
                        <operatorCode>{$operatorCode}</operatorCode>
                        <requestId>{$requestId}</requestId>
                        <affiliateCode>{$affiliateCode}</affiliateCode>
                        <responseCode>000</responseCode>
                        <responseMessage>Success</responseMessage>
                    </mmHeaderInfo>
                    <accountAlias>{$accountAlias}</accountAlias>
                    <ccy>{$currency}</ccy>
                    <availableBalance>{$availableBalance}</availableBalance>
                    <currentBalance>{$availableBalance}</currentBalance>
                </return>
                </b2w:GetAccountBalanceResponse>
            </soapenv:Body>
        </soapenv:Envelope>
XML;

        // Update the transaction status as successful
        $this->updateTransactionStatus($referenceNumber, '000', 'Success', 0);

        // Return the XML response
        return response($xmlResponse, 200)
            ->header('Content-Type', 'application/xml');

    } catch (\Exception $e) {
        // Log the error and update the transaction_statuses table
        Log::error('Error processing GetAccountBalance:', ['error' => $e->getMessage()]);
        $this->updateTransactionStatus($referenceNumber, 'E99', $e->getMessage(), 2);
        return $this->sendError("010","","","",$e->getMessage(),"",null);

        // Return error response
    }
}

/**
 * Helper method to update transaction status in transaction_statuses table
 */
private function updateTransactionStatus($referenceNumber, $responseCode, $responseMessage, $status)
{
    DB::table('transaction_statuses')
        ->where('reference_number', $referenceNumber)
        ->update([
            'response_code' => $responseCode,
            'response_message' => $responseMessage,
            'status' => $status,
            'update_at' => now()
        ]);
}

    private function getBalance($accountAlias)
    {
        try {
            $check=Serveur::setDatabaseConnection($accountAlias);
            if($check===false){
                // Log or handle the error
                Log::error("Database connection failed 2 : ");
                return "Database connection failed";

            }
            $code_membre=substr($accountAlias, -11);
            Log::info("Debut du traitement : ".$code_membre);
            //Get accountNo
            $compte= DB::connection('sqlsrv2')
            ->table('CC.CC_CUENTA_EFECTIVO')
            ->join('CF.CF_PRODUCTOS', 'CF.CF_PRODUCTOS.COD_PRODUCTO', '=', 'CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO')
            ->where('CC.CC_CUENTA_EFECTIVO.COD_CLIENTE', $code_membre)
            ->where('CC.CC_CUENTA_EFECTIVO.IND_ESTADO', 'A')
            ->where(function($query) {
                $query->where('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC004')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC003')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC008');
            })->first();
            //Log::info("Compte infos : ".$compte);
            $solde_client=$compte->SAL_DISPONIBLE ?? 0;
            return $solde_client;
        } catch (\Throwable $th) {
            //throw $th;
            Log::error("Error getting account balance : ".$code_membre."  Log: ".$th->getMessage());
            return "Error getting account balance";
        }

}


private function TransactionB2W($accountAlias,$amount)
{
    $responseCode='010';
    if($this->getBalance($accountAlias)==false){
        return $this->sendError("E01","","","","Account not found","",null);
    }
    else{
        $availableBalance = $this->getBalance($accountAlias);
        if($availableBalance<$amount){
            $responseCode='E16';
            $responseMessage='Insufficient funds';
            //Return them on array data
            return ['responseCode'=>$responseCode,'responseMessage'=>$responseMessage,'availableBalance'=>$availableBalance];
        }
        else{

            Serveur::setDatabaseConnection($accountAlias);
            $code_user=CodeUser::find(1)->code;
            $code_membre=substr($accountAlias, -11);
            //Get accountNo
            $compte= DB::connection('sqlsrv2')
            ->table('CC.CC_CUENTA_EFECTIVO')
            ->join('CF.CF_PRODUCTOS', 'CF.CF_PRODUCTOS.COD_PRODUCTO', '=', 'CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO')
            ->where('CC.CC_CUENTA_EFECTIVO.COD_CLIENTE', $code_membre)
            ->where('CC.CC_CUENTA_EFECTIVO.IND_ESTADO', 'A')
            ->where(function($query) {
                $query->where('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC004')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC003')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC008');
            })->first();
            $accountNo=$compte->NUM_CUENTA;
            $code_agence=$compte->COD_AGENCIA;
            //Get client info
            $info_benef=DB::connection('sqlsrv2')->table('CL.CL_CLIENTES')->where('COD_CLIENTE',$compte->COD_CLIENTE)->orderBy('COD_CLIENTE', 'desc')->first();
            Log::info('Opération B2W / Compte :'.$accountNo.'/ Montant:'.$amount);
            
            $check=SchemaComptable::OperationTransB2W($accountNo,$amount,$code_user,"CC".substr($accountNo,3,3),$info_benef->NOM_CLIENTE,$info_benef->TEL_SECUNDARIO,$code_agence);
            if($check==false){
                $responseCode='E01';
                $responseMessage='Transaction failed';
                //Return them on array data
                return ['responseCode'=>$responseCode,'responseMessage'=>$responseMessage,'availableBalance'=>$availableBalance];
            }
            else{
                 //Get Original Mouvement ID
            $last_mov_id= DB::connection('sqlsrv2')->table('CF.CF_SERIES_X_EMPRESA')->where('COD_SERIE','CC_MOV_DIA')->first()->VAL_SIGUIENTE;
            $last_mov_id_mov=  DB::connection('sqlsrv2')->table('CC.CC_MOVIMTO_DIARIO')->select('NUM_MOVIMIENTO')->orderBy('NUM_MOVIMIENTO', 'desc')->first()->NUM_MOVIMIENTO;
            if($last_mov_id_mov>=$last_mov_id){
                $last_mov_id=$last_mov_id_mov;
            }
            $mouvement_id=$last_mov_id;

            $responseCode='000';
            $responseMessage='Success';
            //Return them on array data
            return ['responseCode'=>$responseCode,'responseMessage'=>$responseMessage,'mouvement_id'=>$mouvement_id];
            }

        }
    }

}

private function TransactionW2B($accountAlias,$amount)
{
    $responseCode='010';
    if($this->getBalance($accountAlias)==false){
        return $this->sendError("E01","","","","Account not found","",null);
    }
    else{
        //$availableBalance = $this->getBalance($accountAlias);

            Serveur::setDatabaseConnection($accountAlias);
            $code_user=CodeUser::find(1)->code;
            $code_membre=substr($accountAlias, -11);
            //Get accountNo
            $compte= DB::connection('sqlsrv2')
            ->table('CC.CC_CUENTA_EFECTIVO')
            ->join('CF.CF_PRODUCTOS', 'CF.CF_PRODUCTOS.COD_PRODUCTO', '=', 'CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO')
            ->where('CC.CC_CUENTA_EFECTIVO.COD_CLIENTE', $code_membre)
            ->where('CC.CC_CUENTA_EFECTIVO.IND_ESTADO', 'A')
            ->where(function($query) {
                $query->where('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC004')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC003')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC008');
            })->first();
            $accountNo=$compte->NUM_CUENTA;
            $code_agence=$compte->COD_AGENCIA;
            //Get client info
            $info_benef=DB::connection('sqlsrv2')->table('CL.CL_CLIENTES')->where('COD_CLIENTE',$compte->COD_CLIENTE)->orderBy('COD_CLIENTE', 'desc')->first();
            Log::info('Opération B2W / Compte :'.$accountNo.'/ Montant:'.$amount);
            $check=SchemaComptable::OperationTransW2B($accountNo,$amount,$code_user,"CC".substr($accountNo,3,3),$info_benef->NOM_CLIENTE,$info_benef->TEL_SECUNDARIO,$code_agence);
            if($check==false){
                $responseCode='E01';
                $responseMessage='Transaction failed';
                //Return them on array data
                return ['responseCode'=>$responseCode,'responseMessage'=>$responseMessage];
            }
            else{
                 //Get Original Mouvement ID
            $last_mov_id= DB::connection('sqlsrv2')->table('CF.CF_SERIES_X_EMPRESA')->where('COD_SERIE','CC_MOV_DIA')->first()->VAL_SIGUIENTE;
            $last_mov_id_mov=  DB::connection('sqlsrv2')->table('CC.CC_MOVIMTO_DIARIO')->select('NUM_MOVIMIENTO')->orderBy('NUM_MOVIMIENTO', 'desc')->first()->NUM_MOVIMIENTO;
            if($last_mov_id_mov>=$last_mov_id){
                $last_mov_id=$last_mov_id_mov;
            }
            $mouvement_id=$last_mov_id;

            $responseCode='000';
            $responseMessage='Success';
            //Return them on array data
            return ['responseCode'=>$responseCode,'responseMessage'=>$responseMessage,'mouvement_id'=>$mouvement_id];
            }


    }

}




private function getMiniStatement($xml)
    {
        try {
            // Extract mmHeaderInfo fields
            $mmHeaderInfo = $xml->xpath('//MiniStatementRequest/mmHeaderInfo')[0];

            $operatorCode = (string) $mmHeaderInfo->operatorCode;
            $requestId = (string) $mmHeaderInfo->requestId;
            $affiliateCode = (string) $mmHeaderInfo->affiliateCode;
            $requestType = (string) $mmHeaderInfo->requestType;

            // Log mmHeaderInfo data for debugging
            Log::info('MiniStatementRequest mmHeaderInfo:', [
                'operatorCode' => $operatorCode,
                'requestId' => $requestId,
                'affiliateCode' => $affiliateCode,
                'requestType' => $requestType,
            ]);
            

            // Extract additional request fields
            $accountNo = (string) $xml->xpath('//MiniStatementRequest/accountNo')[0];
            $accountAlias = (string) $xml->xpath('//MiniStatementRequest/accountAlias')[0];

             // Generate a unique reference number for tracking purposes
        $referenceNumber = uniqid('ref_', true);

        // Log the initial request in the transaction_statuses table
        DB::table('transaction_statuses')->insert([
            'date' => now(),
            'type' => 'GetMiniStatementResponse',
            'alias' => $accountAlias,
            'currency' => 'XOF',
            'amount' => 0,
            'request_code' => $requestId,
            'response_code' => '', // Initially empty, updated after processing
            'response_message' => 'Pending',
            'reference_number' => $referenceNumber,
            'status' => 1, // 1 for pending
            'created_at' => now(),
            'update_at' => now()
        ]);

            //DB CONNEXION
            Serveur::setDatabaseConnection($accountAlias);
            $code_user=CodeUser::find(1)->code;
            $code_membre=substr($accountAlias, -11);
            //Get accountNo
            $compte= DB::connection('sqlsrv2')
            ->table('CC.CC_CUENTA_EFECTIVO')
            ->join('CF.CF_PRODUCTOS', 'CF.CF_PRODUCTOS.COD_PRODUCTO', '=', 'CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO')
            ->where('CC.CC_CUENTA_EFECTIVO.COD_CLIENTE', $code_membre)
            ->where('CC.CC_CUENTA_EFECTIVO.IND_ESTADO', 'A')
            ->where(function($query) {
                $query->where('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC004')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC003')
                      ->orWhere('CC.CC_CUENTA_EFECTIVO.COD_PRODUCTO', 'CC008');
            })->first();
            $accountNo=$compte->NUM_CUENTA;
            //GET MOUVEMENTS

            // Log additional request fields
            Log::info('MiniStatementRequest Data:', [
                'accountNo' => $accountNo,
                'accountAlias' => $accountAlias,
            ]);

            // Simulated transaction data (In a real scenario, retrieve these from the database)
           // Récupérer les 5 dernières opérations
            $transactions = DB::connection('sqlsrv2')
            ->table('CC.CC_MOVIMTO_DIARIO')
            ->where('NUM_CUENTA', $accountNo)
            ->orderByDesc('NUM_MOVIMIENTO')
            ->limit(5)
            ->get(['NUM_MOVIMIENTO', 'FEC_MOVIMIENTO', 'EST_MOVIMIENTO', 'MON_MOVIMIENTO'])
            ->map(function ($operation) {
                return [
                    'tranRefNo' => $operation->NUM_MOVIMIENTO,
                    'tranDate' => Carbon::parse($operation->FEC_MOVIMIENTO)->toIso8601String(),
                    'ccy' => "XOF",
                    'crDr' => $operation->EST_MOVIMIENTO, // Adaptation du type
                    'amount' => (string) $operation->MON_MOVIMIENTO,
                ];
            });

            // Build the success response XML with the specified structure
            $xmlResponse = <<<XML
            <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
            <soap:Body>
                <ns2:GetMiniStatementResponse xmlns:ns2="http://b2w.banktowallet.com/b2w">
                <return>
                    <mmHeaderInfo>
                    <operatorCode>{$operatorCode}</operatorCode>
                    <requestId>{$requestId}</requestId>
                    <affiliateCode>{$affiliateCode}</affiliateCode>
                    <responseCode>000</responseCode>
                    <responseMessage>Success</responseMessage>
                    </mmHeaderInfo>
    XML;

            // Append each transaction to the XML response
            foreach ($transactions as $transaction) {
                $xmlResponse .= <<<XML
                    <TransactionList>
                    <tranRefNo>{$transaction['tranRefNo']}</tranRefNo>
                    <tranDate>{$transaction['tranDate']}</tranDate>
                    <ccy>{$transaction['ccy']}</ccy>
                    <crDr>{$transaction['crDr']}</crDr>
                    <amount>{$transaction['amount']}</amount>
                    </TransactionList>
    XML;
            }

            // Close the response structure
            $xmlResponse .= <<<XML
                </return>
                </ns2:GetMiniStatementResponse>
            </soap:Body>
            </soap:Envelope>
    XML;

            Log::info("MOUVEMENTS:".$xmlResponse);
            // Return the XML response
            return response($xmlResponse, 200)
                ->header('Content-Type', 'application/xml');

        } catch (\Exception $e) {
            Log::error('Error processing GetMiniStatement:', ['error' => $e->getMessage()]);
            $this->updateTransactionStatus($referenceNumber, 'E99', $e->getMessage(), 2);
            return $this->sendError("E01",$operatorCode,$requestId,$affiliateCode,'Account not found',$referenceNumber,"GetMiniStatementResponse");
        }
    }


    private function walletToAccountTransfer($xml)
{
    try {
        // Extract mmHeaderInfo fields from the request XML
        $mmHeaderInfo = $xml->xpath('//MobileTransferRequest/mmHeaderInfo')[0];
        $operatorCode = (string) $mmHeaderInfo->operatorCode;
        $requestId = (string) $mmHeaderInfo->requestId;
        $affiliateCode = (string) $mmHeaderInfo->affiliateCode;
        $requestType = (string) $mmHeaderInfo->requestType;
        $requestToken = (string) $mmHeaderInfo->requestToken;

        // Extract additional request fields
        $accountAlias = (string) $xml->xpath('//MobileTransferRequest/accountAlias')[0];
        $amount = (string) $xml->xpath('//MobileTransferRequest/amount')[0];
        $ccy = (string) $xml->xpath('//MobileTransferRequest/ccy')[0];

        // Generate a unique reference number for tracking purposes
        $referenceNumber = uniqid('ref_', true);

        // Log the request in the transaction_statuses table
        DB::table('transaction_statuses')->insert([
            'date' => now(),
            'type' => 'W2B', // Wallet to Bank
            'alias' => $accountAlias,
            'currency' => $ccy,
            'amount' => $amount,
            'request_code' => $requestId,
            'response_code' => 'Pending', // Initially set as pending
            'response_message' => 'Request received',
            'reference_number' => $referenceNumber,
            'status' => 0, // 0 for pending
            'created_at' => now(),
            'update_at' => now(),
        ]);

        // Log mmHeaderInfo and additional request fields for debugging
        Log::info('WalletToAccountTransfer mmHeaderInfo:', [
            'operatorCode' => $operatorCode,
            'requestId' => $requestId,
            'affiliateCode' => $affiliateCode,
            'requestType' => $requestType,
            'requestToken' => $requestToken,
            'accountAlias' => $accountAlias,
            'amount' => $amount,
            'ccy' => $ccy,
        ]);

        // Process the transfer
        $result = $this->TransactionW2B($accountAlias, $amount);
        $responseCode = $result['responseCode'];
        $responseMessage = $result['responseMessage'];
        $CBAReferenceNo="";
        if ($responseCode == '000') {
            $CBAReferenceNo = date('Y').date('m').random_int(11,99).$result['mouvement_id'];
            // Successful transaction
            $responseMessage = 'Success';

            // Update transaction status to successful
            DB::table('transaction_statuses')
                ->where('reference_number', $referenceNumber)
                ->update([
                    'response_code' => $responseCode,
                    'response_message' => $responseMessage,
                    'status' => 1, // 1 for successful
                    'update_at' => now(),
                ]);

            // Build the success response XML
            $xmlResponse = <<<XML
            <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
              <soap:Body>
                <ns2:WalletToAccountTransferResponse xmlns:ns2="http://b2w.banktowallet.com/b2w">
                  <return>
                    <mmHeaderInfo>
                      <operatorCode>{$operatorCode}</operatorCode>
                      <requestId>{$requestId}</requestId>
                      <affiliateCode>{$affiliateCode}</affiliateCode>
                      <responseCode>000</responseCode>
                      <responseMessage>Success</responseMessage>
                    </mmHeaderInfo>
                    <CBAReferenceNo>{$CBAReferenceNo}</CBAReferenceNo>
                  </return>
                </ns2:WalletToAccountTransferResponse>
              </soap:Body>
            </soap:Envelope>
XML;

            // Return the XML response
            return response($xmlResponse, 200)
                ->header('Content-Type', 'application/xml');
        } else {
            // Transaction failed, update transaction status
            DB::table('transaction_statuses')
                ->where('reference_number', $referenceNumber)
                ->update([
                    'response_code' => $responseCode,
                    'response_message' => $responseMessage,
                    'status' => 0, // 0 for failed
                    'update_at' => now(),
                ]);

            return $this->sendtransfertError($responseCode, $requestId, $operatorCode, $affiliateCode,$CBAReferenceNo);
        }

    } catch (\Exception $e) {
        Log::error('Error processing WalletToAccountTransfer:', ['error' => $e->getMessage()]);

        // Update the transaction log with the error details
        DB::table('transaction_statuses')
            ->where('reference_number', $referenceNumber)
            ->update([
                'response_code' => 'E99',
                'response_message' => $e->getMessage(),
                'status' => 0, // 0 for failed due to error
                'update_at' => now(),
            ]);

            return $this->sendtransfertError($responseCode, $requestId, $operatorCode, $affiliateCode,$CBAReferenceNo);
    }
}





private function accountToWalletTransfer($xml)
{
    try {
        // Extract mmHeaderInfo fields from the request XML
        $mmHeaderInfo = $xml->xpath('//MobileTransferRequest/mmHeaderInfo')[0];
        $operatorCode = (string) $mmHeaderInfo->operatorCode;
        $requestId = (string) $mmHeaderInfo->requestId;
        $affiliateCode = (string) $mmHeaderInfo->affiliateCode;
        $requestToken = (string) $mmHeaderInfo->requestToken;
        $requestType = (string) $mmHeaderInfo->requestType;

        // Extract additional fields from the request
        $externalRefNo = (string) $xml->xpath('//MobileTransferRequest/externalRefNo')[0];
        $accountAlias = (string) $xml->xpath('//MobileTransferRequest/accountAlias')[0];
        $amount = (string) $xml->xpath('//MobileTransferRequest/amount')[0];
        $ccy = (string) $xml->xpath('//MobileTransferRequest/ccy')[0];
        $tranDate = (string) $xml->xpath('//MobileTransferRequest/tranDate')[0];

        // Generate a unique reference number for tracking purposes
        $referenceNumber = uniqid('ref_', true);

        // Log the initial request in the transaction_statuses table
        DB::table('transaction_statuses')->insert([
            'date' => $tranDate,
            'type' => 'AccountToWalletTransfer',
            'alias' => $accountAlias,
            'currency' => $ccy,
            'amount' => $amount,
            'request_code' => $requestId,
            'response_code' => '', // Initially empty, updated after processing
            'response_message' => 'Pending',
            'reference_number' => $referenceNumber,
            'status' => 1, // 1 for pending
            'created_at' => now(),
            'update_at' => now()
        ]);

        // Process the transaction
        $result = $this->TransactionB2W($accountAlias, $amount);
        $responseCode = $result['responseCode'];
        $responseMessage = $result['responseMessage'];
        $CBAReferenceNo="";
        if ($responseCode == '000') {
            $CBAReferenceNo = date('Y').date('m').random_int(11,99).$result['mouvement_id'];
            // Transaction was successful

            // Update the transaction_statuses table with success details
            DB::table('transaction_statuses')
                ->where('reference_number', $referenceNumber)
                ->update([
                    'response_code' => $responseCode,
                    'response_message' => $responseMessage,
                    'status' => 0, // 0 for success
                    'update_at' => now()
                ]);

            // Build the success XML response
            $xmlResponse = <<<XML
            <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
              <soap:Body>
                <ns2:AccountToWalletTransferResponse xmlns:ns2="http://b2w.banktowallet.com/b2w">
                  <return>
                    <mmHeaderInfo>
                      <operatorCode>{$operatorCode}</operatorCode>
                      <requestId>{$requestId}</requestId>
                      <affiliateCode>{$affiliateCode}</affiliateCode>
                      <responseCode>{$responseCode}</responseCode>
                      <responseMessage>{$responseMessage}</responseMessage>
                    </mmHeaderInfo>
                    <CBAReferenceNo>{$CBAReferenceNo}</CBAReferenceNo>
                  </return>
                </ns2:AccountToWalletTransferResponse>
              </soap:Body>
            </soap:Envelope>
XML;


            // Return the XML response
            return response($xmlResponse, 200)
                ->header('Content-Type', 'application/xml');
        } else {
            // Transaction failed; update the transaction_statuses table
            DB::table('transaction_statuses')
                ->where('reference_number', $referenceNumber)
                ->update([
                    'response_code' => $responseCode,
                    'response_message' => $responseMessage,
                    'status' => 2, // 2 for failure
                    'update_at' => now()
                ]);

            // Return the failure response
            return $this->sendtransfertError($responseCode, $requestId, $operatorCode, $affiliateCode, $CBAReferenceNo);
        
        }

    } catch (\Exception $e) {
        // Log the error for debugging
        Log::error('Error processing AccountToWalletTransfer:', ['error' => $e->getMessage()]);

        // Update the transaction_statuses table with error details
        DB::table('transaction_statuses')
            ->where('reference_number', $referenceNumber)
            ->update([
                'response_code' => 'E99', // Custom error code
                'response_message' => $e->getMessage(),
                'status' => 2, // 2 for failure
                'update_at' => now()
            ]);

        // Return error response
        return $this->sendtransfertError($responseCode, $requestId, $operatorCode, $affiliateCode, $CBAReferenceNo);
    }
}


private function transferStatusInquiry($xml)
{
    try {
        // Extract mmHeaderInfo fields from the request XML
        $mmHeaderInfo = $xml->xpath('//TranRequestInfo/mmHeaderInfo')[0];
        $operatorCode = (string) $mmHeaderInfo->operatorCode;
        $requestId = (string) $mmHeaderInfo->requestId;
        $affiliateCode = (string) $mmHeaderInfo->affiliateCode;

        // Extract the externalRefNo from the request
        $externalRefNo = (string) $xml->xpath('//TranRequestInfo/externalRefNo')[0];

        // Log the request for debugging
        Log::info('TransferStatusInquiry Request:', [
            'operatorCode' => $operatorCode,
            'requestId' => $requestId,
            'affiliateCode' => $affiliateCode,
            'externalRefNo' => $externalRefNo,
        ]);

        // Simulated response code (example: 'E16' for insufficient balance)
        $responseCode = '000';
        $CBAReferenceNo = 'BANK99999991234';

        // Fetch the response message based on the code
        $responseMessage = $this->getReturnCodeDescription($responseCode);

        // Build the XML response structure
        $xmlResponse = <<<XML
        <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
          <S:Body>
            <ns2:TransferStatusInquiryResponse xmlns:ns2="http://b2w.banktowallet.com/b2w">
              <return>
                <mmHeaderInfo>
                  <operatorCode>{$operatorCode}</operatorCode>
                  <requestId>{$requestId}</requestId>
                  <affiliateCode>{$affiliateCode}</affiliateCode>
                  <responseCode>{$responseCode}</responseCode>
                  <responseMessage>{$responseMessage}</responseMessage>
                </mmHeaderInfo>
                <CBAReferenceNo>{$CBAReferenceNo}</CBAReferenceNo>
              </return>
            </ns2:TransferStatusInquiryResponse>
          </S:Body>
        </S:Envelope>
XML;

        // Return the XML response
        return response($xmlResponse, 200)
            ->header('Content-Type', 'application/xml');

    } catch (\Exception $e) {
        // Log the error for debugging
        Log::error('Error processing TransferStatusInquiry:', ['error' => $e->getMessage()]);
        return $this->sendError("010","","","",$e->getMessage(),"",null);
    }
}




private function sendError($responseCode,$operatorCode,$requestId,$affiliateCode,$responseMessage,$CBAReferenceNo,$action)
{

    if($action==null){
        $errorXml = '<?xml version="1.0" encoding="UTF-8"?>';
        $errorXml .= '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">';
        $errorXml .= '<soapenv:Body>';
        $errorXml .= '<soapenv:Fault>';
        $errorXml .= '<faultcode>SOAP-ENV:Client</faultcode>';
        $errorXml .= '<responseCode>' . $responseCode . '</responseCode>';
        $errorXml .= '<faultstring>' . $responseMessage . '</faultstring>';
        $errorXml .= '</soapenv:Fault>';
        $errorXml .= '</soapenv:Body>';
        $errorXml .= '</soapenv:Envelope>';

    }
    else{
        $errorXml = '<?xml version="1.0" encoding="UTF-8"?>';
        $errorXml .= '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">';
        $errorXml .= '<soap:Body>';
        $errorXml .= '<ns2:' . $action . ' xmlns:ns2="http://b2w.banktowallet.com/b2w">';
        $errorXml .= '<return>';
        $errorXml .= '<mmHeaderInfo>';
        $errorXml .= '<operatorCode>' . $operatorCode . '</operatorCode>';
        $errorXml .= '<requestId>' . $requestId . '</requestId>';
        $errorXml .= '<affiliateCode>' . $affiliateCode . '</affiliateCode>';
        $errorXml .= '<responseCode>' . $responseCode . '</responseCode>';
        $errorXml .= '<responseMessage>' . $responseMessage . '</responseMessage>';
        $errorXml .= '</mmHeaderInfo>';
        $errorXml .= '<CBAReferenceNo>' . $CBAReferenceNo . '</CBAReferenceNo>';
        $errorXml .= '</return>';
        $errorXml .= '</ns2:' . $action . '>';
        $errorXml .= '</soap:Body>';
        $errorXml .= '</soap:Envelope>';

    }
    Log::info("ErrorResponse : ".$errorXml);


    return response($errorXml, 500)
        ->header('Content-Type', 'application/xml');
}
private static function sendtransfertError($responseCode, $requestId,$operatorCode,$affiliateCode, $CBAReferenceNo)
{
    $instance = new self();
    $responseMessage = $instance->getReturnCodeDescription($responseCode);

    $errorXml = '<?xml version="1.0" encoding="UTF-8"?>';
    $errorXml .= '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">';
    $errorXml .= '<soap:Body>';
    $errorXml .= '<ns2:TransferStatusInquiryResponse xmlns:ns2="http://b2w.banktowallet.com/b2w">';
    $errorXml .= '<return>';
    $errorXml .= '<mmHeaderInfo>';
    $errorXml .= '<operatorCode>' . $operatorCode . '</operatorCode>';
    $errorXml .= '<requestId>' . $requestId . '</requestId>';
    $errorXml .= '<affiliateCode>' . $affiliateCode . '</affiliateCode>';
    $errorXml .= '<responseCode>' . $responseCode . '</responseCode>';
    $errorXml .= '<responseMessage>' . $responseMessage . '</responseMessage>';
    $errorXml .= '</mmHeaderInfo>';
    $errorXml .= '<CBAReferenceNo>' . $CBAReferenceNo . '</CBAReferenceNo>';
    $errorXml .= '</return>';
    $errorXml .= '</ns2:TransferStatusInquiryResponse>';
    $errorXml .= '</soap:Body>';
    $errorXml .= '</soap:Envelope>';


    Log::info("ErrorResponseCode : ".$errorXml);

    return response($errorXml, 500)
        ->header('Content-Type', 'application/xml');
}



// Define an associative array of return codes and descriptions
private function getReturnCodeDescription($code)
{
    $errorCodes = [
        '000' => 'Success',
        '010' => 'Bank Technical Error',
        'E01' => 'Bank Technical Error',
        'E02' => 'Bank Technical Error',
        'E03' => 'Bank Technical Error',
        'E04' => 'Bank Technical Error',
        'E05' => 'Bank Technical Error',
        'E06' => 'Bank Technical Error',
        'E07' => 'Bank Technical Error',
        'E08' => 'Bank Technical Error',
        'E09' => 'Bank Technical Error',
        'E10' => 'Bank Technical Error',
        'E11' => 'Operation in Timeout. Use TransferStatusInquiry to check status',
        'E12' => 'Bank Technical Error',
        'E13' => 'Unauthorized Request on Account (crossed thresholds)',
        'E14' => 'Unauthorized Request on Account (crossed thresholds)',
        'E15' => 'Unauthorized Request on Account (crossed thresholds)',
        'E16' => 'Insufficient Balance',
        'E17' => 'Bank Technical Error',
        'E18' => 'Bank Technical Error',
        'E19' => 'Bank Technical Error',
        'E20' => 'Bank Technical Error',
        'E21' => 'Bank Technical Error',
        'E22' => 'Transaction Violates Account\'s Minimum Balance',
        'E35' => 'Bank Technical Error',
        'E99' => 'Bank Technical Error',
    ];

    // Return the description for the given code, or a default message if the code is not found
    return isset($errorCodes[$code]) ? $errorCodes[$code] : 'Unknown Error';
}










//First example method teste pass ok


// public function getAccountBalance(Request $request)
//     {
//     // Retrieve the raw XML request
//     $xmlRequest = $request->getContent();


//     // Use internal error handling for libxml
//     libxml_use_internal_errors(true);

//     // Try to create a SimpleXMLElement
//     try {
//         $xml = new SimpleXMLElement($xmlRequest);
//     } catch (Exception $e) {
//         throw new Exception("Failed to parse XML: " . $e->getMessage());
//     }

//     // Check for XML parsing errors
//     if (libxml_get_errors()) {
//         $errors = libxml_get_errors();
//         libxml_clear_errors();
//         throw new Exception("XML Errors: " . implode(", ", array_map(fn($error) => $error->message, $errors)));
//     }

//     // Print the parsed XML for debugging
//     //print_r($xml);

//     // Register the namespaces for XPath queries
//     $xml->registerXPathNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
//     $xml->registerXPathNamespace('ns1', 'http://b2w.banktowallet.com/b2w');

//     // Get the SOAP body
//     $body = $xml->xpath('//soapenv:Body');

//     if (empty($body)) {
//         throw new Exception("No SOAP body found in the response.");
//     }

//     // Get the specific response (e.g., GetAccountBalance)
//     $accountBalance = $body[0]->xpath('//ns1:GetAccountBalance');

//     if (empty($accountBalance)) {
//         throw new Exception("No GetAccountBalance found in the response.");
//     }

//     // Convert the body to JSON and then decode it
//     $json = json_encode((array)$accountBalance[0], JSON_THROW_ON_ERROR);
//     $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);

//     $operatorCode = $data['AccountBalanceInquiryRequest']['mmHeaderInfo']['operatorCode'] ?? null;
//     $requestId = $data['AccountBalanceInquiryRequest']['mmHeaderInfo']['requestId']?? null;
//     $requestToken = $data['AccountBalanceInquiryRequest']['mmHeaderInfo']['requestToken']?? null;
//     $requestType = $data['AccountBalanceInquiryRequest']['mmHeaderInfo']['requestType']?? null;
//     $affiliateCode = $data['AccountBalanceInquiryRequest']['mmHeaderInfo']['affiliateCode']?? null;
//     $accountNo = $data['AccountBalanceInquiryRequest']['accountNo']?? null;
//     $accountAlias = $data['AccountBalanceInquiryRequest']['accountAlias']?? null;
//     //return $data;

//     //GET BALANCES SOLDE
//     $availableBalance=$this->getBalance($accountNo);
//     $ccy="XOF";


//         // Construct the response XML
//         $responseXml = <<<XML
//         <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:b2w="http://b2w.banktowallet.com/b2w">
//             <soapenv:Header/>
//             <soapenv:Body>
//                 <b2w:GetAccountBalanceResponse>
//                 <return>
//                     <mmHeaderInfo>
//                         <operatorCode>$operatorCode</operatorCode>
//                         <requestId>$requestId</requestId>
//                         <affiliateCode>$affiliateCode</affiliateCode>
//                         <responseCode>000</responseCode>
//                         <responseMessage>Success</responseMessage>
//                     </mmHeaderInfo>
//                     <accountAlias>$accountAlias</accountAlias>
//                     <ccy>$ccy</ccy>
//                     <availableBalance>$availableBalance</availableBalance>
//                     <currentBalance>$availableBalance</currentBalance>
//                 </return>

//                 </b2w:GetAccountBalanceResponse>
//             </soapenv:Body>
//         </soapenv:Envelope>
//         XML;

//         return response($responseXml, 200)
//             ->header('Content-Type', 'text/xml');

// }


}




