<?php

namespace App\Services\Communications\Providers;

use App\Contracts\Communications\SmsChannelProvider;
use App\Enum\Contact\MessageProvider;
use App\Models\Contact\Hub\ContactMessage;
use App\ValueObjects\Communications\ProviderSendResult;
use RuntimeException;
use Twilio\Rest\Client as TwilioClient;

class TwilioSmsProvider implements SmsChannelProvider
{
    public function identifier(): MessageProvider
    {
        return MessageProvider::TWILIO;
    }

    public function send(ContactMessage $message): ProviderSendResult
    {
        if (empty($message->recipient_phone)) {
            throw new RuntimeException('ContactMessage is missing recipient_phone.');
        }

        $from = $message->sender_value ?: config('services.twilio.sms_from_fallback');
        if (empty($from)) {
            throw new RuntimeException('No Twilio "from" number configured for this send.');
        }

        $accountSid = config('services.twilio.sid');
        $authToken = config('services.twilio.token');

        $smsSender = $message->smsSender;
        $subaccountSid = $smsSender?->twilio_subaccount_sid;

        $client = new TwilioClient($accountSid, $authToken);

        $params = [
            'from' => $from,
            'body' => (string) $message->body_text,
        ];

        // Twilio rejects statusCallback when the "from" is an alpha tag
        // (one-way), so we only include it for real numbers.
        if (!$smsSender || $smsSender->isNumber()) {
            $params['statusCallback'] = $this->statusCallbackUrl($message);
        }

        if ($subaccountSid) {
            $response = $client->api->v2010
                ->accounts($subaccountSid)
                ->messages
                ->create($message->recipient_phone, $params);
        } else {
            $response = $client->messages->create($message->recipient_phone, $params);
        }

        $providerMessageId = $response->sid;

        $payload = [
            'sid' => $response->sid,
            'status' => $response->status,
            'num_segments' => $response->numSegments,
            'price' => $response->price,
            'date_created' => $response->dateCreated instanceof \DateTimeInterface
                ? $response->dateCreated->format(\DateTimeInterface::ATOM)
                : null,
        ];

        return new ProviderSendResult(
            providerMessageId: $providerMessageId,
            payload: $payload,
            accepted: !in_array($response->status, ['failed', 'undelivered'], true),
        );
    }

    private function statusCallbackUrl(ContactMessage $message): string
    {
        $base = rtrim((string) config('services.twilio.webhook_base_url'), '/');
        $path = config('contact.webhooks.twilio.sms_status', '/webhooks/contact/twilio/sms/status');
        return $base . $path . '?mid=' . $message->id;
    }
}
