<?php
class TelstraAPI
{
    private $clientId;
    private $clientSecret;
    private $tokenUrl = 'https://tapi.telstra.com/v2/oauth/token';
    private $apiBaseUrl = 'https://products.api.telstra.com/messaging/v3/';
    private $tokenFile = __DIR__ . '/token_cache.json';
    private $lastAuthError = '';

    public function __construct()
    {
        if (!function_exists('curl_init')) {
            throw new \Exception('The PHP cURL extension is missing. Please enable extension=curl in your php.ini file and restart your server.');
        }

        // Load from .env file if it exists
        $this->loadEnv(__DIR__ . '/.env');

        // Try environment variables first, then fall back to hardcoded credentials
        $this->clientId = getenv('TELSTRA_CLIENT_ID') ?: ($_ENV['TELSTRA_CLIENT_ID'] ?? ($_SERVER['TELSTRA_CLIENT_ID'] ?? ''));
        $this->clientSecret = getenv('TELSTRA_CLIENT_SECRET') ?: ($_ENV['TELSTRA_CLIENT_SECRET'] ?? ($_SERVER['TELSTRA_CLIENT_SECRET'] ?? ''));

        // If no environment variables, we cannot proceed
        if (empty($this->clientId) || empty($this->clientSecret)) {
            $this->lastAuthError = 'Telstra API credentials missing. Please set TELSTRA_CLIENT_ID and TELSTRA_CLIENT_SECRET in your server environment or .env file.';
        }
    }

    private function loadEnv($path)
    {
        if (!file_exists($path))
            return;

        $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        if ($lines === false)
            return;
        foreach ($lines as $line) {
            if (strpos(trim($line), '#') === 0)
                continue;
            $parts = explode('=', $line, 2);
            if (count($parts) === 2) {
                $name = trim($parts[0]);
                $value = trim($parts[1], " \t\n\r\0\x0B\"'");
                if (function_exists('putenv')) {
                    putenv(sprintf('%s=%s', $name, $value));
                }
                $_ENV[$name] = $value;
                $_SERVER[$name] = $value;
            }
        }
    }

    /**
     * Verbose logging engine for the Admin Panel
     */
    private function logApiActivity($endpoint, $request, $httpCode, $response, $error)
    {
        $logFile = __DIR__ . '/api_log.json';
        $log = file_exists($logFile) ? json_decode((string) @file_get_contents($logFile), true) : [];
        if (!is_array($log))
            $log = [];

        // Redact sensitive data before logging
        if (is_string($request)) {
            $request = preg_replace('/client_secret=[^&]+/', 'client_secret=***REDACTED***', $request);
        }
        $responseDecoded = json_decode((string) $response, true);
        if (is_array($responseDecoded) && isset($responseDecoded['access_token'])) {
            $responseDecoded['access_token'] = '***REDACTED***';
            $response = json_encode($responseDecoded);
        }

        $requestPayload = $request;
        if (is_string($request)) {
            $decodedRequest = json_decode($request, true);
            if (is_array($decodedRequest)) {
                $requestPayload = $decodedRequest;
            }
        }

        $log[] = [
            'timestamp' => date('Y-m-d H:i:s'),
            'endpoint' => $endpoint,
            'request_payload' => $requestPayload,
            'http_code' => $httpCode,
            'response_body' => is_array($responseDecoded) ? $responseDecoded : $response,
            'curl_error' => $error
        ];

        // Keep the last 100 logs to prevent file bloat
        if (count($log) > 100)
            $log = array_slice($log, -100);
        @file_put_contents($logFile, json_encode($log, JSON_PRETTY_PRINT | JSON_INVALID_UTF8_SUBSTITUTE), LOCK_EX);
    }

    /**
     * Retrieve a cached OAuth token or request a new one from Telstra.
     */
    public function getAccessToken()
    {
        if (empty($this->clientId) || empty($this->clientSecret)) {
            $this->lastAuthError = 'API credentials missing. Please ensure your .env file is uploaded to the server.';
            return null;
        }

        if (file_exists($this->tokenFile)) {
            $cached = json_decode((string) @file_get_contents($this->tokenFile), true);
            if ($cached && isset($cached['expires_at']) && $cached['expires_at'] > time()) {
                return $cached['access_token'];
            }
        }

        $postFields = http_build_query([
            'grant_type' => 'client_credentials',
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret,
            'scope' => 'free-trial-numbers:read free-trial-numbers:write messages:read messages:write reports:read reports:write virtual-numbers:read virtual-numbers:write'
        ]);

        $curlOpts = [
            CURLOPT_URL => $this->tokenUrl,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $postFields,
            CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
            CURLOPT_TIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2
        ];

        // Use bundled cacert.pem if it exists
        if (file_exists(__DIR__ . '/cacert.pem')) {
            $curlOpts[CURLOPT_CAINFO] = __DIR__ . '/cacert.pem';
        }

        $ch = curl_init();
        curl_setopt_array($ch, $curlOpts);
        $response = curl_exec($ch);
        $curlError = curl_error($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $this->logApiActivity('POST /oauth/token', $postFields, $httpCode, $response, $curlError);

        if ($curlError) {
            $this->lastAuthError = 'cURL error: ' . $curlError;
            return null;
        }

        $data = json_decode((string) $response, true);
        if (!isset($data['access_token'])) {
            $errorField = is_array($data) ? ($data['error_description'] ?? $data['error'] ?? null) : null;
            if (is_array($errorField)) {
                $errorField = $errorField['message'] ?? $errorField['description'] ?? json_encode($errorField);
            }
            $this->lastAuthError = $errorField ?: 'API responded with: ' . $response;
            return null;
        }

        $cacheData = [
            'access_token' => $data['access_token'],
            'expires_at' => time() + ($data['expires_in'] ?? 3600) - 60
        ];
        @file_put_contents($this->tokenFile, json_encode($cacheData, JSON_PRETTY_PRINT), LOCK_EX);

        return $data['access_token'];
    }

    /**
     * Send an SMS message using the Telstra Messaging API v3.
     */
    public function sendMessage($to, $message, $from = null, $retry = true)
    {
        if (!$to || !$message) {
            return ['success' => false, 'error' => 'Invalid destination number or message text.'];
        }

        $token = $this->getAccessToken();
        if (!$token) {
            return ['success' => false, 'error' => 'Auth failed: ' . ($this->lastAuthError ?: 'Unknown error.')];
        }

        $payload = [
            'to' => $this->normalizePhoneNumber($to),
            'messageContent' => trim($message)
        ];
        if ($from) {
            $payload['from'] = $this->normalizePhoneNumber($from);
        }

        $curlOpts = [
            CURLOPT_URL => $this->apiBaseUrl . 'messages',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($payload, JSON_INVALID_UTF8_SUBSTITUTE),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $token
            ],
            CURLOPT_TIMEOUT => 15,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2
        ];
        if (file_exists(__DIR__ . '/cacert.pem')) {
            $curlOpts[CURLOPT_CAINFO] = __DIR__ . '/cacert.pem';
        }

        $ch = curl_init();
        curl_setopt_array($ch, $curlOpts);
        $response = curl_exec($ch);
        $curlError = curl_error($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $this->logApiActivity('POST /messages', json_encode($payload), $httpCode, $response, $curlError);

        if ($httpCode === 401 && $retry) {
            @unlink($this->tokenFile);
            return $this->sendMessage($to, $message, $from, false);
        }

        if ($curlError) {
            return ['success' => false, 'error' => 'Telstra request error: ' . $curlError];
        }

        $data = json_decode((string) $response, true);
        if ($httpCode === 200 || $httpCode === 201 || $httpCode === 202) {
            $messageId = is_array($data) ? ($data['messageId'] ?? null) : null;
            return ['success' => true, 'messageId' => $messageId];
        }

        $errorField = is_array($data) ? ($data['error'] ?? $data['message'] ?? null) : null;
        if (is_array($errorField)) {
            $errorField = $errorField['message'] ?? $errorField['description'] ?? json_encode($errorField);
        }
        $rawPreview = is_string($response) ? substr($response, 0, 300) : '';
        $errorMsg = $errorField ?: 'Telstra SMS request failed. Raw response: ' . $rawPreview;
        return ['success' => false, 'error' => 'HTTP ' . $httpCode . ': ' . $errorMsg];
    }

    /**
     * Request a new dedicated number (Virtual Number) from the Telstra API v3.
     */
    public function provisionNumber($retry = true)
    {
        $token = $this->getAccessToken();
        if (!$token) {
            return ['success' => false, 'error' => 'Auth failed: ' . ($this->lastAuthError ?: 'Unknown error.')];
        }

        // Provision a virtual number (v3)
        $curlOpts = [
            CURLOPT_URL => $this->apiBaseUrl . 'virtual-numbers',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => "{}",
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $token
            ],
            CURLOPT_TIMEOUT => 15,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2
        ];
        if (file_exists(__DIR__ . '/cacert.pem')) {
            $curlOpts[CURLOPT_CAINFO] = __DIR__ . '/cacert.pem';
        }

        $ch = curl_init();
        curl_setopt_array($ch, $curlOpts);
        $response = curl_exec($ch);
        $curlError = curl_error($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $this->logApiActivity('POST /virtual-numbers', "{}", $httpCode, $response, $curlError);

        if ($httpCode === 401 && $retry) {
            @unlink($this->tokenFile);
            return $this->provisionNumber(false);
        }

        if ($curlError) {
            return ['success' => false, 'error' => 'Telstra request error: ' . $curlError];
        }

        $data = json_decode((string) $response, true);
        if ($httpCode === 200 || $httpCode === 201) {
            $number = is_array($data) ? ($data['virtualNumber'] ?? 'Unknown') : 'Unknown';
            return ['success' => true, 'number' => $number];
        }

        $errorField = is_array($data) ? ($data['error'] ?? $data['message'] ?? null) : null;
        if (is_array($errorField)) {
            $errorField = $errorField['message'] ?? $errorField['description'] ?? json_encode($errorField);
        }
        $rawPreview = is_string($response) ? substr($response, 0, 300) : '';
        $errorMsg = $errorField ?: 'Telstra provisioning failed. Raw response: ' . $rawPreview;
        return ['success' => false, 'error' => 'HTTP ' . $httpCode . ': ' . $errorMsg];
    }

    /**
     * Retrieve the latest status for a sent SMS message.
     */
    public function getMessageStatus($messageId, $retry = true)
    {
        if (!$messageId) {
            return null;
        }

        $token = $this->getAccessToken();
        if (!$token) {
            return null;
        }

        $curlOpts = [
            CURLOPT_URL => $this->apiBaseUrl . 'messages/' . urlencode($messageId),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $token,
                'Accept: application/json'
            ],
            CURLOPT_TIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2
        ];
        if (file_exists(__DIR__ . '/cacert.pem')) {
            $curlOpts[CURLOPT_CAINFO] = __DIR__ . '/cacert.pem';
        }

        $ch = curl_init();
        curl_setopt_array($ch, $curlOpts);
        $response = curl_exec($ch);
        $curlError = curl_error($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $this->logApiActivity('GET /messages/...', null, $httpCode, $response, $curlError);

        if ($httpCode === 401 && $retry) {
            @unlink($this->tokenFile);
            return $this->getMessageStatus($messageId, false);
        }

        if ($httpCode === 200) {
            return json_decode((string) $response, true);
        }

        return null;
    }

    /**
     * Basic placeholder for webhook signature validation.
     */
    public function validateWebhookSignature($body, $signature)
    {
        return true;
    }

    private function normalizePhoneNumber($number)
    {
        $clean = preg_replace('/[^0-9\+]/', '', $number);
        if (strpos($clean, '+') !== 0) {
            if (strpos($clean, '61') === 0) {
                $clean = '+' . $clean;
                // Fix an accidental leading zero: +6104... to +614...
                $clean = preg_replace('/^\+610/', '+61', $clean);
            } elseif (strpos($clean, '04') === 0) {
                $clean = '+61' . substr($clean, 1);
            } else {
                $clean = '+' . $clean;
            }
        }
        return $clean;
    }

    /**
     * Get the last authentication error message.
     */
    public function getLastAuthError()
    {
        return $this->lastAuthError;
    }
}