<?php

namespace App\Services\Channels;

use App\Models\ChannelIntegration;
use App\Models\Message;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

class ChannelMessageSender
{
    public function send(Message $message): Message
    {
        $message->loadMissing('conversation.contact', 'conversation.organization.channelIntegrations');

        $provider = $this->providerForChannel($message->conversation->channel);

        if ($provider === null) {
            return $this->markDelivered($message, null);
        }

        $integration = $message->conversation->organization->channelIntegrations
            ->first(fn (ChannelIntegration $integration): bool => $integration->provider === $provider && $integration->enabled);

        if ($integration === null) {
            return $this->markFailed($message, $provider, 'Channel integration is not connected.');
        }

        if (empty($integration->access_token)) {
            return $this->markFailed($message, $provider, 'Channel access token is missing.');
        }

        if (empty($message->conversation->contact->external_id)) {
            return $this->markFailed($message, $provider, 'Customer external channel id is missing.');
        }

        return match ($provider) {
            'facebook' => $this->sendFacebook($message, $integration),
            'whatsapp' => $this->sendWhatsApp($message, $integration),
            default => $this->markFailed($message, $provider, 'Unsupported delivery provider.'),
        };
    }

    private function sendFacebook(Message $message, ChannelIntegration $integration): Message
    {
        $endpoint = $this->graphEndpoint($integration->external_id.'/messages');

        $response = Http::withToken($integration->access_token)
            ->acceptJson()
            ->post($endpoint, [
                'recipient' => [
                    'id' => $message->conversation->contact->external_id,
                ],
                'messaging_type' => 'RESPONSE',
                'message' => [
                    'text' => $message->body,
                ],
            ]);

        return $this->recordProviderResponse($message, 'facebook', $response, $response->json('message_id'));
    }

    private function sendWhatsApp(Message $message, ChannelIntegration $integration): Message
    {
        $settings = $integration->settings ?? [];
        $phoneNumberId = $settings['phone_number_id'] ?? $integration->external_id;
        $endpoint = $this->graphEndpoint($phoneNumberId.'/messages');

        $response = Http::withToken($integration->access_token)
            ->acceptJson()
            ->post($endpoint, [
                'messaging_product' => 'whatsapp',
                'to' => $message->conversation->contact->external_id,
                'type' => 'text',
                'text' => [
                    'preview_url' => false,
                    'body' => $message->body,
                ],
            ]);

        return $this->recordProviderResponse($message, 'whatsapp', $response, $response->json('messages.0.id'));
    }

    private function recordProviderResponse(Message $message, string $provider, Response $response, ?string $providerMessageId): Message
    {
        if ($response->successful()) {
            return $this->markDelivered($message, $provider, $providerMessageId);
        }

        return $this->markFailed($message, $provider, Str::limit($response->body(), 1000, ''));
    }

    private function markDelivered(Message $message, ?string $provider, ?string $providerMessageId = null): Message
    {
        $message->forceFill([
            'provider' => $provider,
            'provider_message_id' => $providerMessageId ?? $message->provider_message_id,
            'delivery_status' => 'sent',
            'delivery_error' => null,
            'delivered_at' => now(),
        ])->save();

        return $message;
    }

    private function markFailed(Message $message, string $provider, string $error): Message
    {
        $message->forceFill([
            'provider' => $provider,
            'delivery_status' => 'failed',
            'delivery_error' => $error,
            'delivered_at' => null,
        ])->save();

        return $message;
    }

    private function providerForChannel(string $channel): ?string
    {
        return match ($channel) {
            'facebook', 'messenger' => 'facebook',
            'whatsapp' => 'whatsapp',
            default => null,
        };
    }

    private function graphEndpoint(string $path): string
    {
        $baseUrl = rtrim((string) config('services.meta.graph_base_url', 'https://graph.facebook.com'), '/');
        $version = trim((string) config('services.meta.graph_version', 'v23.0'), '/');

        return $baseUrl.'/'.$version.'/'.ltrim($path, '/');
    }
}
