<?php

namespace App\Services;

use App\Models\Business;
use App\Models\Setting;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Http;
use RuntimeException;
use Throwable;

class SmsGatewayService
{
    private const NEXTSMS_HOST = 'messaging-service.co.tz';

    private const NEXTSMS_SINGLE_MESSAGE_PATH = '/api/sms/v1/text/single';

    /**
     * Send one SMS using the configured gateway.
     *
     * @return array{successful: bool, status: int|null, recipient: string, response: string}
     */
    public function send(Business $business, string $recipient, string $message): array
    {
        $settings = Setting::query()
            ->where('business_id', $business->id)
            ->where('group', 'sms')
            ->pluck('value', 'key');

        $apiUrl = trim((string) $settings->get('sms_api_url'));
        $senderId = trim((string) $settings->get('sms_sender_id'));
        $encryptedApiKey = $settings->get('sms_api_key') ?: $settings->get('sms_bearer_token');
        $timeout = max(3, min(60, (int) ($settings->get('sms_timeout_seconds') ?: 15)));

        if ($apiUrl === '' || $senderId === '' || blank($encryptedApiKey)) {
            throw new RuntimeException('SMS gateway is not fully configured. Save the API URL, Sender ID and API Key first.');
        }

        $apiUrl = $this->resolveApiUrl($apiUrl);

        try {
            $apiKey = Crypt::decryptString((string) $encryptedApiKey);
        } catch (Throwable) {
            throw new RuntimeException('The saved SMS API Key could not be read. Save the credential again.');
        }

        $normalizedRecipient = $this->normalizeTanzanianNumber($recipient);

        try {
            $response = Http::acceptJson()
                ->asJson()
                ->timeout($timeout)
                ->withHeaders([
                    'Authorization' => 'Basic '.$apiKey,
                ])
                ->post($apiUrl, [
                    'from' => $senderId,
                    'to' => $normalizedRecipient,
                    'text' => $message,
                ]);
        } catch (Throwable) {
            return [
                'successful' => false,
                'status' => null,
                'recipient' => $normalizedRecipient,
                'response' => 'Could not connect to the SMS provider. Check the API URL, server network access and gateway credentials.',
            ];
        }

        $providerResponse = trim($response->body());
        if ($providerResponse === '') {
            $providerResponse = $response->successful()
                ? 'The SMS provider accepted the request without a response body.'
                : 'The SMS provider returned an empty response.';
        }

        return [
            'successful' => $response->successful(),
            'status' => $response->status(),
            'recipient' => $normalizedRecipient,
            'response' => mb_substr($providerResponse, 0, 1000),
        ];
    }

    public function normalizeTanzanianNumber(string $number): string
    {
        $digits = preg_replace('/\D+/', '', trim($number)) ?? '';

        if (str_starts_with($digits, '0')) {
            $digits = '255'.substr($digits, 1);
        }

        if (! preg_match('/^255\d{9}$/', $digits)) {
            throw new RuntimeException('Enter a valid Tanzanian mobile number, for example 0756123456 or 255756123456.');
        }

        return $digits;
    }

    private function resolveApiUrl(string $apiUrl): string
    {
        $parts = parse_url($apiUrl);

        if ($parts === false || ! isset($parts['scheme'], $parts['host'])) {
            throw new RuntimeException('The SMS API URL is invalid. Save a complete HTTPS endpoint and try again.');
        }

        $host = strtolower((string) $parts['host']);
        $path = (string) ($parts['path'] ?? '');

        if ($host === self::NEXTSMS_HOST && ($path === '' || $path === '/')) {
            $port = isset($parts['port']) ? ':'.$parts['port'] : '';

            return $parts['scheme'].'://'.$parts['host'].$port.self::NEXTSMS_SINGLE_MESSAGE_PATH;
        }

        return $apiUrl;
    }
}
