<?php
/**
 * SMS sending (Arkesel or Twilio)
 * Requires: config/sms.php
 */

function getSmsConfig() {
    static $config = null;
    if ($config === null) {
        $fileConfig = require __DIR__ . '/../config/sms.php';
        if (!function_exists('getSettingsByPrefix')) {
            require_once __DIR__ . '/settings.php';
        }
        $db = getSettingsByPrefix('sms_');
        if (!empty($db)) {
            $config = array_merge($fileConfig, [
                'enabled'      => !empty($db['enabled']),
                'provider'     => $db['provider'] ?? $fileConfig['provider'],
                'api_key'      => $db['api_key'] ?? $fileConfig['api_key'],
                'from_sender'  => $db['from_sender'] ?? $fileConfig['from_sender'],
                'account_sid'  => $db['account_sid'] ?? $fileConfig['account_sid'],
                'auth_token'   => $db['auth_token'] ?? $fileConfig['auth_token'],
                'from_number'  => $db['from_number'] ?? $fileConfig['from_number'],
            ]);
        } else {
            $config = $fileConfig;
        }
    }
    return $config;
}

/**
 * Send SMS to multiple recipients in as few API calls as possible.
 *
 * @param array  $phones  List of phone numbers (raw, will be normalised)
 * @param string $message Body text
 * @return array ['sent' => int, 'failed' => int, 'total' => int, 'errors' => string[]]
 */
function sendBulkSms(array $phones, string $message): array {
    $cfg = getSmsConfig();
    if (empty($cfg['enabled'])) {
        return ['sent' => 0, 'failed' => count($phones), 'total' => count($phones), 'errors' => ['SMS is not configured or disabled.']];
    }

    // Normalise all numbers
    $normalised = [];
    foreach ($phones as $p) {
        $n = normalisePhone($p);
        if ($n !== '') $normalised[] = $n;
    }
    $normalised = array_values(array_unique($normalised));
    $total = count($normalised);
    if ($total === 0) {
        return ['sent' => 0, 'failed' => 0, 'total' => 0, 'errors' => []];
    }

    if ($cfg['provider'] === 'arkesel') {
        return sendBulkSmsArkesel($cfg, $normalised, $message);
    }

    // Twilio: no native bulk endpoint — send individually
    $sent = $failed = 0;
    $errors = [];
    foreach ($normalised as $phone) {
        $res = sendSmsTwilio($cfg, $phone, $message);
        if ($res['sent']) { $sent++; } else {
            $failed++;
            if ($res['error'] && !in_array($res['error'], $errors)) $errors[] = $res['error'];
        }
    }
    return ['sent' => $sent, 'failed' => $failed, 'total' => $total, 'errors' => $errors];
}

/**
 * Send Arkesel bulk SMS — all numbers in one request (comma-separated 'to').
 * Chunks into batches of 100 to avoid URL-length limits.
 */
function sendBulkSmsArkesel(array $cfg, array $normalisedPhones, string $message): array {
    $apiKey = $cfg['api_key'] ?? '';
    $from   = $cfg['from_sender'] ?? 'Arkesel';
    if ($apiKey === '') {
        return ['sent' => 0, 'failed' => count($normalisedPhones), 'total' => count($normalisedPhones), 'errors' => ['Arkesel API key not set.']];
    }

    // Convert to Arkesel digit format (no + or spaces, 233xxxxxxxxx)
    $toDigitsList = array_map(function($p) {
        $d = preg_replace('/\D/', '', $p);
        if (strlen($d) === 10) $d = '233' . $d;
        return $d;
    }, $normalisedPhones);

    $total  = count($toDigitsList);
    $sent   = 0;
    $failed = 0;
    $errors = [];

    // Arkesel batch: comma-separate numbers, max 100 per request
    foreach (array_chunk($toDigitsList, 100) as $chunk) {
        $toParam = implode(',', $chunk);
        $url = 'https://sms.arkesel.com/sms/api?action=send-sms'
            . '&api_key=' . rawurlencode($apiKey)
            . '&to='      . rawurlencode($toParam)
            . '&from='    . rawurlencode($from)
            . '&sms='     . rawurlencode($message);

        $ctx = stream_context_create(['http' => ['timeout' => 30, 'ignore_errors' => true]]);
        $response = @file_get_contents($url, false, $ctx);

        if ($response === false) {
            $failed += count($chunk);
            $errors[] = 'Failed to reach Arkesel API.';
            continue;
        }

        $data = @json_decode($response, true);
        $ok = false;
        if (is_array($data)) {
            $code = $data['code'] ?? $data['success'] ?? null;
            $ok = ($code === 'ok' || $code === true);
            if (!$ok && isset($data['message']) && stripos((string)$data['message'], 'success') !== false) {
                $ok = true;
            }
            if (!$ok) {
                $err = $data['message'] ?? $response;
                if (!in_array($err, $errors)) $errors[] = $err;
            }
        } else {
            $err = $response ?: 'Empty response from Arkesel.';
            if (!in_array($err, $errors)) $errors[] = $err;
        }

        if ($ok) {
            $sent += count($chunk);
        } else {
            $failed += count($chunk);
        }
    }

    return ['sent' => $sent, 'failed' => $failed, 'total' => $total, 'errors' => $errors];
}

/**
 * Normalise a phone number to Arkesel/E.164-style digits.
 */
function normalisePhone(string $phone): string {
    $p = preg_replace('/\s+/', '', $phone);
    if ($p === '') return '';
    // Already has country code prefix (+ or 233...)
    if (substr($p, 0, 1) === '+') return $p;
    // Local 10-digit Ghana number
    if (strlen($p) === 10 && substr($p, 0, 1) === '0') {
        return '+233' . substr($p, 1);
    }
    return $p;
}

/**
 * Send an SMS.
 *
 * @param string $to      E.164 number (e.g. +233241234567)
 * @param string $message Body (max length depends on provider; Twilio 1600 chars)
 * @return array ['sent' => bool, 'error' => string|null]
 */
function sendSms($to, $message) {
    $cfg = getSmsConfig();
    if (empty($cfg['enabled'])) {
        return ['sent' => false, 'error' => 'SMS is not configured or disabled.'];
    }

    $to = preg_replace('/\s+/', '', $to);
    if (substr($to, 0, 1) !== '+') {
        $to = '+' . ltrim($to, '0');
        if (strlen($to) === 10) {
            $to = '+233' . $to;
        }
    }

    if ($cfg['provider'] === 'arkesel') {
        return sendSmsArkesel($cfg, $to, $message);
    }
    if ($cfg['provider'] === 'twilio') {
        return sendSmsTwilio($cfg, $to, $message);
    }

    return ['sent' => false, 'error' => 'Unknown SMS provider: ' . ($cfg['provider'] ?? '')];
}

/**
 * Check Arkesel SMS balance.
 *
 * @param string $apiKey Arkesel API key
 * @return array ['balance' => int|null, 'error' => string|null] balance in units (e.g. SMS credits), or null on error
 */
function getArkeselBalance($apiKey) {
    $apiKey = trim($apiKey ?? '');
    if ($apiKey === '') {
        return ['balance' => null, 'error' => 'API key not set.'];
    }
    $url = 'https://sms.arkesel.com/sms/api?action=check-balance&api_key=' . rawurlencode($apiKey) . '&response=json';
    $ctx = stream_context_create([
        'http' => [
            'timeout' => 2,
            'ignore_errors' => true
        ]
    ]);
    $response = @file_get_contents($url, false, $ctx);
    if ($response === false) {
        return ['balance' => null, 'error' => 'Could not reach Arkesel API.'];
    }
    $data = @json_decode($response, true);
    if (!is_array($data)) {
        return ['balance' => null, 'error' => 'Invalid response from API.'];
    }
    if (isset($data['balance']) && is_numeric($data['balance'])) {
        return ['balance' => (int) $data['balance'], 'error' => null];
    }
    $err = $data['message'] ?? $data['error'] ?? 'Unknown response.';
    return ['balance' => null, 'error' => $err];
}

function sendSmsArkesel(array $cfg, $to, $message) {
    $apiKey = $cfg['api_key'] ?? '';
    $from = $cfg['from_sender'] ?? 'Arkesel';
    if ($apiKey === '') {
        return ['sent' => false, 'error' => 'Arkesel API key not set.'];
    }
    // Arkesel expects digits only (e.g. 233241234567)
    $toDigits = preg_replace('/\D/', '', $to);
    if (strlen($toDigits) === 10) {
        $toDigits = '233' . $toDigits;
    }
    $url = 'https://sms.arkesel.com/sms/api?action=send-sms'
        . '&api_key=' . rawurlencode($apiKey)
        . '&to=' . rawurlencode($toDigits)
        . '&from=' . rawurlencode($from)
        . '&sms=' . rawurlencode($message);

    $ctx = stream_context_create([
        'http' => [
            'timeout' => 15,
            'ignore_errors' => true
        ]
    ]);
    $response = @file_get_contents($url, false, $ctx);
    if ($response === false) {
        return ['sent' => false, 'error' => 'Failed to reach Arkesel API.'];
    }
    $data = @json_decode($response, true);
    if (is_array($data)) {
        $code = $data['code'] ?? $data['success'] ?? null;
        $ok = ($code === 'ok' || $code === true);
        if (!$ok && isset($data['message']) && stripos((string) $data['message'], 'success') !== false) {
            $ok = true;
        }
        if ($ok) {
            return ['sent' => true, 'error' => null];
        }
        $err = $data['message'] ?? $response;
    } else {
        $err = $response;
    }
    return ['sent' => false, 'error' => $err];
}

function sendSmsTwilio(array $cfg, $to, $message) {
    $sid = $cfg['account_sid'] ?? '';
    $token = $cfg['auth_token'] ?? '';
    $from = $cfg['from_number'] ?? '';
    if ($sid === '' || $token === '' || $from === '') {
        return ['sent' => false, 'error' => 'Twilio credentials or from_number not set.'];
    }

    $url = 'https://api.twilio.com/2010-04-01/Accounts/' . rawurlencode($sid) . '/Messages.json';
    $body = http_build_query([
        'To'   => $to,
        'From' => $from,
        'Body' => $message,
    ]);

    $ctx = stream_context_create([
        'http' => [
            'method'  => 'POST',
            'header'  => "Content-Type: application/x-www-form-urlencoded\r\nAuthorization: Basic " . base64_encode($sid . ':' . $token),
            'content' => $body,
            'timeout' => 2,
            'ignore_errors' => true
        ],
    ]);

    $response = @file_get_contents($url, false, $ctx);
    if ($response === false) {
        return ['sent' => false, 'error' => 'Failed to reach Twilio API.'];
    }

    $data = json_decode($response, true);
    if (isset($data['sid'])) {
        return ['sent' => true, 'error' => null];
    }
    $err = $data['message'] ?? $response;
    return ['sent' => false, 'error' => $err];
}
