<?php

namespace App\Libraries;

// Allow this legacy CI3-style library to be included under different
// environments (CodeIgniter 3 or 4). Avoid exiting when BASEPATH
// is not defined so the file can be loaded by the CI4-based app.
if (!defined('BASEPATH') && !defined('SYSTEMPATH')) {
    if (!defined('CI_LEGACY')) {
        define('CI_LEGACY', true);
    }
}

require_once __DIR__ . '/ExecutorBase.php';

class SmsExecutor extends ExecutorBase {

    private $username;
    private $password;
    private $from;
    private $verify_ssl = true;
    private $lastResponse = null;

    public function __construct() {
        parent::__construct('sms');
        // Load credentials and settings from environment variables (secure, configurable)
        $this->username   = env('SMS_USERNAME', '') ?: env('SMS_USER', '') ?: getenv('SMS_USERNAME') ?: getenv('SMS_USER') ?: 'PHILIPOLUBUVA';
        $this->password   = env('SMS_PASSWORD', '') ?: getenv('SMS_PASSWORD') ?: 'kiswahili';
        $this->from       = env('SMS_FROM', '')     ?: getenv('SMS_FROM')     ?: 'AP DIGITAL';
        $this->verify_ssl = filter_var(env('SMS_VERIFY_SSL', 'true') ?: 'true', FILTER_VALIDATE_BOOLEAN);
    }

    // Method to execute SMS tasks
    protected function executeTask($messages, $isLast = true) {
        if (count($messages) == 1) {
            $sms = json_encode($this->asSms($messages[0]));
            log_message('debug', 'Sending single SMS: ' . $sms);
            $this->sendNexByteSms('single', $sms);
        } else {
            log_message('debug', 'Sending multiple SMS');
            $sms = array_map(fn($m) => $this->asSms($m), $messages);
            $msgs = json_encode(['messages' => $sms]);
            $this->sendNexByteSms('multi', $msgs);
        }
    }

    // Normalize a phone number to international format (255XXXXXXXXX for Tanzania)
    private function normalizePhone(string $phone): string {
        $phone = preg_replace('/\D/', '', $phone); // strip non-digits
        if (str_starts_with($phone, '0') && strlen($phone) === 10) {
            return '255' . substr($phone, 1); // 0715465042 → 255715465042
        }
        if (str_starts_with($phone, '+')) {
            return ltrim($phone, '+');         // +255715465042 → 255715465042
        }
        return $phone;
    }

    // Method to send a single or multiple SMS
    public function sendSms($recipient, $text, $reference = null) {
        if (empty($recipient) || empty($text)) {
            log_message('error', 'SMS sending failed: recipient number or message text is missing.');
            return false;
        }

        // Normalize to international format
        $recipients = array_map(
            fn($r) => $this->normalizePhone((string) $r),
            is_array($recipient) ? $recipient : [$recipient]
        );

    $smsPayload = [
        'from' => $this->from,
        'to' => $recipients,
        'text' => $text,
        'reference' => $reference ?? uniqid()
    ];

    $postJson = json_encode($smsPayload);
    log_message('error', '[SMS] Sending to: ' . implode(',', (array)$smsPayload['to']) . ' | from: ' . $this->from . ' | user: ' . $this->username);

    $response = $this->sendNexByteSms('single', $postJson);
    log_message('error', '[SMS] API Response: ' . json_encode($response));

    if ($response === false) {
        log_message('error', 'SMS API request failed (HTTP/cURL error).');
        return false;
    }

    $success = false;
    if (is_array($response)) {
        if (isset($response['success']) && $response['success']) {
            $success = true;
        } elseif (!empty($response['results'])) {
            $success = true;
        } elseif (isset($response['statusCode']) && $response['statusCode'] >= 200 && $response['statusCode'] < 300) {
            $success = true;
        } elseif (isset($response['status']) && strtolower($response['status']) === 'ok') {
            $success = true;
        }
    }

    if ($success) {
        log_message('info', '✅ SMS sent successfully to: ' . implode(',', (array)$smsPayload['to']));
        return true;
    } else {
        log_message('error', '❌ SMS sending reported failure by API: ' . json_encode($response));
        return false;
    }
}


// Helper method to send the SMS request to Nextbyte
private function sendNexByteSms($path, $postJson) {
    // Generate the Base64 encoded authorization key from username and password
    $key = base64_encode("$this->username:$this->password");

    // Construct the URL based on the path parameter
    $url = "https://messaging-service.co.tz/api/sms/v1/text/$path";

    // Initialize cURL and set options
    $curl = curl_init();
    curl_setopt_array($curl, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "POST",
        CURLOPT_POSTFIELDS => $postJson,
        CURLOPT_HTTPHEADER => array(
            "Accept: application/json",
            "Authorization: Basic $key",
            "Content-Type: application/json"
        ),
        CURLOPT_SSL_VERIFYPEER => $this->verify_ssl
    ));

    // Execute the cURL request
    $response = curl_exec($curl);
    $err = curl_error($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);

    // Log the HTTP response
    log_message('error', '[SMS] HTTP ' . $httpCode . ' | raw: ' . $response);

    // Check if there was an error during the request
    if ($err) {
        log_message('error', '[SMS] cURL Error: ' . $err);
        return false;
    }

    // Parse the API response
    $response_data = json_decode($response, true);

    // Attach HTTP status code to the response data for downstream checks
    if (!is_array($response_data)) {
        $response_data = ['raw' => $response];
    }
    $response_data['statusCode'] = $httpCode;

    // Return the response data for further processing
    // Save last raw/parsed response for debugging
    $this->lastResponse = $response_data;
    return $response_data;
}

    /**
     * Get the last provider response (parsed or raw wrapper)
     */
    public function getLastResponse() {
        return $this->lastResponse;
    }


    // Method to fetch delivery report based on messageId
    // Method to fetch delivery report based on messageId with exponential backoff retry mechanism
private function fetchDeliveryReport($messageId, $maxRetries = 5, $initialDelay = 2) {
    $key = base64_encode("$this->username:$this->password");
    $url = "https://messaging-service.co.tz/api/sms/v1/reports?messageId=" . urlencode($messageId);

    $attempt = 0;
    $delay = $initialDelay;

    while ($attempt < $maxRetries) {
        // Initialize cURL and set options
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => array(
                "Accept: application/json",
                "Authorization: Basic $key",
                "Content-Type: application/json"
            ),
            CURLOPT_SSL_VERIFYPEER => $this->verify_ssl
        ));

        // Execute the cURL request
        $response = curl_exec($curl);
        $err = curl_error($curl);
        curl_close($curl);

        // Log the response for troubleshooting
        log_message('debug', 'Fetch Delivery Report Response: ' . $response);

        // Check if there was an error during the request
        if ($err) {
            log_message('error', 'cURL Error: ' . $err);
            return false;
        }

        $response_data = json_decode($response, true);

        // Check the status of the delivery report
        if (isset($response_data['results'][0]['status']['groupId'])) {
            $statusGroupId = $response_data['results'][0]['status']['groupId'];
            $statusDescription = $response_data['results'][0]['status']['description'];

            if ($statusGroupId == 3) { // Delivered status group
                log_message('debug', 'SMS delivered successfully: ' . $statusDescription);
                return true;
            } else {
                log_message('error', 'SMS not delivered: ' . $statusDescription);
                return false;
            }
        }

        // Handle 429 Too Many Requests response
        if (strpos($response, '429 Too Many Requests') !== false) {
            log_message('error', 'Rate limit exceeded. Waiting before retrying...');
        } else {
            log_message('debug', 'No delivery report found. Retrying...');
        }

        // Increment attempt count and delay time for exponential backoff
        $attempt++;
        sleep($delay); // Wait before retrying
        $delay *= 2; // Exponential backoff - double the delay each time
    }

    log_message('error', 'No delivery report found or unknown error occurred after multiple attempts.');
    return false;
}
}
