<?php

require_once __DIR__ . '/../config/config.php';

class MTNMoMo
{
    private string $baseUrl;
    private string $subscriptionKey;
    private string $apiUser;
    private string $apiKey;
    private string $targetEnvironment;
    private string $currency;

    public function __construct()
    {
        $this->baseUrl           = rtrim(MOMO_BASE_URL, '/');
        $this->subscriptionKey   = SUBSCRIPTION_KEY;
        $this->apiUser           = API_USER;
        $this->apiKey            = API_KEY;
        $this->targetEnvironment = TARGET_ENVIRONMENT;
        $this->currency          = CURRENCY;
    }

    /**
     * Generate UUID v4
     */
    public function generateUUID(): string
    {
        $data = random_bytes(16);

        $data[6] = chr((ord($data[6]) & 0x0f) | 0x40);
        $data[8] = chr((ord($data[8]) & 0x3f) | 0x80);

        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
    }

    /**
     * Get MTN Access Token
     */
    public function getAccessToken(): array
{
    $url = $this->baseUrl . "/collection/token/";

    $credentials = base64_encode(
        $this->apiUser . ":" . $this->apiKey
    );

    $headers = [
        "Authorization: Basic " . $credentials,
        "Ocp-Apim-Subscription-Key: " . $this->subscriptionKey,
        "Content-Type: application/json",
        "Content-Length: 0",
        "User-Agent: Mozilla/5.0"
    ];

    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, "");
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        return [
            "success" => false,
            "error" => curl_error($ch)
        ];
    }

    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    curl_close($ch);

    return [
        "success" => ($httpCode >= 200 && $httpCode < 300),
        "http_code" => $httpCode,
        "response" => json_decode($response, true),
        "raw" => $response
    ];
}
     

         /**
     * Request To Pay
     *
     * @param string $phone
     * @param float|int $amount
     * @param string $externalId
     * @param string $payerMessage
     * @param string $payeeNote
     * @return array
     */
    public function requestToPay(
        string $phone,
        float|int $amount,
        string $externalId = "",
        string $payerMessage = "SmartPrint Payment",
        string $payeeNote = "Printing Service"
    ): array
    {

        // Get Access Token
        $tokenData = $this->getAccessToken();

        if (!$tokenData['success']) {
            return $tokenData;
        }

        if (!isset($tokenData['response']['access_token'])) {

            return [
                "success" => false,
                "message" => "Unable to obtain access token.",
                "token_response" => $tokenData
            ];

        }

        $accessToken = $tokenData['response']['access_token'];

        // Generate Request Reference
        $referenceId = $this->generateUUID();

        if (empty($externalId)) {
            $externalId = time();
        }

        $url = $this->baseUrl . "/collection/v1_0/requesttopay";

        $headers = [

            "Authorization: Bearer {$accessToken}",
            "X-Reference-Id: {$referenceId}",
            "X-Target-Environment: {$this->targetEnvironment}",
            "Ocp-Apim-Subscription-Key: {$this->subscriptionKey}",
            "Content-Type: application/json"

        ];

        $body = [

            "amount" => number_format($amount, 2, '.', ''),
            "currency" => $this->currency,

            "externalId" => (string)$externalId,

            "payer" => [

                "partyIdType" => "MSISDN",
                "partyId" => $phone

            ],

            "payerMessage" => $payerMessage,
            "payeeNote" => $payeeNote

        ];

        $result = $this->sendRequest(
            "POST",
            $url,
            $headers,
            $body
        );

        // Save Reference ID for status checking
        $result['referenceId'] = $referenceId;

        return $result;

    }

    /**
 * Check Payment Status
 */
public function checkPaymentStatus(string $referenceId): array
{
    // Get Access Token
    $tokenData = $this->getAccessToken();

    if (!$tokenData['success']) {
        return $tokenData;
    }

    if (!isset($tokenData['response']['access_token'])) {
        return [
            "success" => false,
            "message" => "Unable to obtain access token."
        ];
    }

    $accessToken = $tokenData['response']['access_token'];

    $url = $this->baseUrl .
        "/collection/v1_0/requesttopay/" .
        $referenceId;

    $headers = [

        "Authorization: Bearer {$accessToken}",
        "X-Target-Environment: {$this->targetEnvironment}",
        "Ocp-Apim-Subscription-Key: {$this->subscriptionKey}"

    ];

    return $this->sendRequest(
        "GET",
        $url,
        $headers
    );
}

    /**
     * Send CURL Request
     */
    private function sendRequest(
        string $method,
        string $url,
        array $headers = [],
        ?array $body = null
    ): array
    {

        $curl = curl_init();

        curl_setopt_array($curl, [

            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => strtoupper($method),
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_TIMEOUT => 60,

            
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,

        ]);

        if ($body !== null) {

            curl_setopt(
                $curl,
                CURLOPT_POSTFIELDS,
                json_encode($body)
            );

        }

        $response = curl_exec($curl);

        $error = curl_error($curl);

        $httpCode = curl_getinfo(
            $curl,
            CURLINFO_HTTP_CODE
        );

        curl_close($curl);

        if ($error) {

            return [

                "success" => false,
                "http_code" => $httpCode,
                "error" => $error

            ];

        }

        return [

            "success" => ($httpCode >= 200 && $httpCode < 300),
            "http_code" => $httpCode,
            "response" => json_decode($response, true),
            "raw" => $response

        ];
    }

}