<?php

namespace App\Helpers;

use GuzzleHttp\Client;

/**
 * This class is used to interact with the EStoreSMS API. It contains methods for sending SMS messages, checking the balance, getting a list of airtime and data products, generating airtime pins, and querying transactions. It also contains private variables for the username, password, sender, and URLs for each of the API endpoints.
 */
class EstoreSMS
{
    private string $username;
    private string $password;
    private string $sender;
    private string $email;

    private $urls = [
        'sms' => "http://www.estoresms.com/smsapi.php?",
        'airtime' => "https://estoresms.com/network_list/v/2",
        'data' => "https://estoresms.com/data_list/v/2",
        'query' => "https://estoresms.com/api_query",
        'pin' => "https://estoresms.com/network_processing/v/2",
    ];


    /**
     * Constructor for the class.
     *
     * @param string $username The username for authentication.
     * @param string $password The password for authentication.
     * @param string $sender The sender of the message.
     * @param string $email The email of the user account.
     */
    public function __construct() {
        $this->email = CONFIG['SMS']['email'];
        $this->username = CONFIG['username'];
        $this->password = CONFIG['SMS']['password'];
        $this->sender = CONFIG['SMS']['sender'];
    }

    public function sendSMS($recipient, $message)
    {
        return $this->makeRequest('GET', $this->buildUrl('sms', [
            'recipient' => $recipient,
            'message' => $message,
        ]));
    }

    public function sendBulkSMS($recipients, $message)
    {
        return $this->makeRequest('GET', $this->buildUrl('sms', [
            'recipient' => implode(",", $recipients),
            'message' => $message,
        ]));
    }

    private function buildUrl(string $type, array $params = []): string
    {
        $params = array_merge($params, [
            'username' => $this->username,
            'password' => $this->password,
            'sender' => $this->sender,
        ]);

        return $this->urls[$type] . http_build_query($params);
    }

    public function checkBalance()
    {
        $url = $this->buildUrl('sms', ['balance' => true]);
        return $this->makeRequest('GET', $url);
    }

    public function getAirtimeProductList(string $phone, string $token, string $country, string $ref): string {
        $hash = hash('sha512', $token . $this->email . $this->username . $ref);
        $data = array(
            "username" => $this->username,
            "hash" => $hash,
            "phone" => $phone,
            "country" => $country
        );
        return $this->makeRequest("POST", $this->urls['airtime'], $data);
    }

    public function getDataProductList(string $phone, string $token, string $ref): string {
        $hash = hash('sha512', $token . $this->email . $this->username . $ref);
        $data = array(
            "username" => $this->username,
            "hash" => $hash,
            "phone" => $phone
        );
        return $this->makeRequest("POST", $this->urls['data'], $data);
    }

    public function generateAirtimePin(string $ref, string $token, int $pinAmount, string $callback, string $pinMessage = '', int $count = 1): string {

        $hash = hash('sha512', $token . $this->email . $this->username . $ref);

        $data = array(
            "username" => $this->username,
            "ref" => $ref,
            "hash" => $hash,
            "callback" => $callback,
            "pinAmount" => $pinAmount,
            "count" => $count,
            "pinMessage" => $pinMessage
        );

        return $this->makeRequest("POST", $this->urls['pin'], $data);
    }

    public function queryTransaction(string $ref, $token) {
        $hash = hash('sha512', $token . $this->email . $this->username . $ref);
        $data = array(
            "username" => $this->username,
            "hash" => $hash,
            "ref" => $ref
        );
        return $this->makeRequest("POST", $this->urls['query'], $data);
    }

    private function makeRequest($method, $url, $data = null) {
        $client = new Client();

        $options = [
            'http_errors' => false,
            'headers' => [
                'Content-Type' => 'application/json',
                'Accept' => 'application/json'
            ],
        ];

        if ($method !== "GET") {
            $options['json'] = $data;
        }

        $response = $client->request($method, $url, $options);

        $statusCode = $response->getStatusCode();
        $body = (string) $response->getBody();

        if ($statusCode >= 400) {
            throw new \Exception("HTTP Error: " . $statusCode . " " . $body);
        } else {
            return json_decode($body, true);
        }
    }
}
