<?php
declare(strict_types=1);

namespace App\Modules\Settings;

use App\Core\Http\SslCertificateResolver;

final class SmsplanetApiClient
{
    private const API_URL = 'https://api2.smsplanet.pl/sms';
    private const AUTH_TOKEN = 'token';

    public function __construct(private readonly int $timeoutSeconds = 15)
    {
    }

    /**
     * @param array<string, mixed> $credentials
     * @return array{ok: bool, http_code: int, message: string, message_id: string}
     */
    public function sendSms(array $credentials, string $phone, string $message): array
    {
        $payload = [
            'from' => trim((string) ($credentials['sender'] ?? '')),
            'to' => trim($phone),
            'msg' => $message,
        ];

        if (!empty($credentials['clear_polish'])) {
            $payload['clear_polish'] = '1';
        }
        if (!empty($credentials['transactional'])) {
            $payload['transactional'] = '1';
        }

        $headers = [];
        if (($credentials['auth_method'] ?? '') === self::AUTH_TOKEN) {
            $headers[] = 'Authorization: Bearer ' . trim((string) ($credentials['api_token'] ?? ''));
        } else {
            $payload['key'] = trim((string) ($credentials['api_key'] ?? ''));
            $payload['password'] = (string) ($credentials['api_password'] ?? '');
        }

        [$body, $httpCode, $curlError] = $this->postForm($payload, $headers);
        if ($curlError !== null) {
            return [
                'ok' => false,
                'http_code' => $httpCode,
                'message' => 'Blad polaczenia: ' . $curlError,
                'message_id' => '',
            ];
        }

        return $this->parseResponse($body, $httpCode);
    }

    /**
     * @param array<string, string> $payload
     * @param array<int, string> $extraHeaders
     * @return array{0: string, 1: int, 2: ?string}
     */
    private function postForm(array $payload, array $extraHeaders): array
    {
        $ch = curl_init(self::API_URL);
        if ($ch === false) {
            return ['', 0, 'Nie udalo sie zainicjowac cURL.'];
        }

        $headers = array_merge([
            'Accept: application/json',
            'Content-Type: application/x-www-form-urlencoded; charset=UTF-8',
            'User-Agent: orderPRO/1.0',
        ], $extraHeaders);

        $options = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query($payload),
            CURLOPT_TIMEOUT => $this->timeoutSeconds,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_HTTPHEADER => $headers,
        ];

        $caPath = SslCertificateResolver::resolve();
        if ($caPath !== null) {
            $options[CURLOPT_CAINFO] = $caPath;
        }

        curl_setopt_array($ch, $options);
        $rawBody = curl_exec($ch);
        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_error($ch);
        unset($ch);

        if ($rawBody === false) {
            return ['', $httpCode, $curlError !== '' ? $curlError : 'Brak odpowiedzi z API.'];
        }

        return [(string) $rawBody, $httpCode, null];
    }

    /**
     * @return array{ok: bool, http_code: int, message: string, message_id: string}
     */
    private function parseResponse(string $body, int $httpCode): array
    {
        $decoded = json_decode(ltrim($body, "\xEF\xBB\xBF \t\n\r\0\x0B"), true);
        if (!is_array($decoded)) {
            return [
                'ok' => false,
                'http_code' => $httpCode,
                'message' => 'Niepoprawna odpowiedz JSON SMSPLANET: ' . substr(trim(strip_tags($body)), 0, 180),
                'message_id' => '',
            ];
        }

        $messageId = trim((string) ($decoded['messageId'] ?? ''));
        if ($httpCode >= 200 && $httpCode < 300 && $messageId !== '') {
            return [
                'ok' => true,
                'http_code' => $httpCode,
                'message' => 'messageId: ' . $messageId,
                'message_id' => $messageId,
            ];
        }

        $errorCode = trim((string) ($decoded['errorCode'] ?? ''));
        $errorMessage = trim((string) ($decoded['errorMsg'] ?? ''));
        if ($errorMessage === '') {
            $errorMessage = 'HTTP ' . $httpCode;
        }
        if ($errorCode !== '') {
            $errorMessage = 'errorCode ' . $errorCode . ': ' . $errorMessage;
        }

        return [
            'ok' => false,
            'http_code' => $httpCode,
            'message' => $errorMessage,
            'message_id' => '',
        ];
    }
}
