<?php

declare(strict_types=1);

namespace ImovelZapAi\Conversations\Application\Actions;

use ImovelZapAi\Conversations\Application\Services\MessagingAdapterResolver;
use ImovelZapAi\Conversations\Application\Services\MessagingConfigResolver;
use ImovelZapAi\Conversations\Domain\Enums\MessageDeliveryStatus;
use ImovelZapAi\Conversations\Domain\Enums\MessageDirection;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ContactModel;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ConversationModel;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\MessageModel;
use ImovelZapAi\Organizations\Application\Services\PlanLimitGuard;
use ImovelZapAi\Organizations\Domain\Exceptions\PlanLimitExceededException;
use ImovelZapAi\Tenancy\Support\TenantContext;
use RuntimeException;

final class SendOutboundMessageAction
{
    public function __construct(
        private readonly MessagingConfigResolver $configResolver,
        private readonly MessagingAdapterResolver $adapterResolver,
        private readonly OpenConversationAction $openConversation,
        private readonly PlanLimitGuard $planLimitGuard,
    ) {}

    public function execute(
        string $tenantId,
        ContactModel $contact,
        string $body,
        ?ConversationModel $conversation = null,
    ): MessageModel {
        TenantContext::set($tenantId);

        try {
            $this->planLimitGuard->assertCanSendWhatsAppMessage($tenantId);
        } catch (PlanLimitExceededException $exception) {
            throw new RuntimeException($exception->getMessage(), 0, $exception);
        }

        $config = $this->configResolver->resolveForTenant($tenantId);
        $conversation ??= $this->openConversation->execute($tenantId, $contact);

        $message = MessageModel::query()->create([
            'tenant_id' => $tenantId,
            'conversation_id' => $conversation->id,
            'direction' => MessageDirection::Outbound,
            'body' => $body,
            'message_type' => 'text',
            'delivery_status' => MessageDeliveryStatus::Pending,
        ]);

        try {
            $adapter = $this->adapterResolver->forConfig($config);
            $providerMessageId = $adapter->sendText($config, $contact->wa_id, $body);

            $message->update([
                'provider_message_id' => $providerMessageId,
                'delivery_status' => MessageDeliveryStatus::Sent,
                'sent_at' => now(),
            ]);
        } catch (\Throwable $exception) {
            $message->update([
                'delivery_status' => MessageDeliveryStatus::Failed,
                'failed_at' => now(),
                'error_message' => $exception->getMessage(),
            ]);
        }

        $conversation->update(['last_message_at' => now()]);

        return $message->fresh() ?? $message;
    }
}
