<?php

declare(strict_types=1);

namespace ImovelZapAi\Automation\Application\Services;

use App\Models\User;
use Illuminate\Support\Facades\Log;
use ImovelZapAi\Automation\Domain\Enums\ActionKey;
use ImovelZapAi\Automation\Domain\Enums\LogLevel;
use ImovelZapAi\Automation\Infrastructure\Persistence\Eloquent\AutomationActionModel;
use ImovelZapAi\Automation\Infrastructure\Persistence\Eloquent\AutomationExecutionModel;
use ImovelZapAi\Automation\Infrastructure\Persistence\Eloquent\AutomationLogModel;
use ImovelZapAi\Sales\Application\Actions\CreateDealTaskAction;
use ImovelZapAi\Sales\Domain\Enums\DealTaskType;
use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;

class ActionRunner
{
    public function __construct(
        private readonly CreateDealTaskAction $createDealTask,
    ) {}

    /**
     * @param  array<string, mixed>  $context
     */
    public function run(
        AutomationExecutionModel $execution,
        AutomationActionModel $action,
        array $context,
        ?User $actor = null,
    ): void {
        $rawKey = (string) ($action->getRawOriginal('action_key') ?? '');
        $key = ActionKey::tryFrom($rawKey);

        if ($key === null) {
            $this->log($execution, LogLevel::Warning, 'Ação desconhecida ignorada.', ['action_key' => $rawKey]);

            return;
        }

        if ($key === ActionKey::Wait) {
            $this->log($execution, LogLevel::Info, 'Aguardando '.$action->delay_seconds.' segundos.', [
                'delay_seconds' => $action->delay_seconds,
            ]);

            return;
        }

        match ($key) {
            ActionKey::CreateNotification => $this->createNotification($execution, $action, $context),
            ActionKey::CreateTask => $this->createTask($execution, $action, $context, $actor),
            ActionKey::CreateReminder => $this->createReminder($execution, $action, $context, $actor),
            ActionKey::SendWhatsapp => $this->sendWhatsapp($execution, $action, $context),
            ActionKey::SendEmail => $this->sendEmail($execution, $action, $context),
            ActionKey::MoveDealStage => $this->stubAction($execution, $key, 'Mudança de etapa registrada'),
            ActionKey::AssignBroker => $this->stubAction($execution, $key, 'Atribuição de corretor registrada'),
            ActionKey::GenerateDocument => $this->stubAction($execution, $key, 'Geração de documento registrada'),
            ActionKey::RequestDocuments => $this->stubAction($execution, $key, 'Solicitação de documentos registrada'),
            ActionKey::StartSignature => $this->stubAction($execution, $key, 'Assinatura registrada'),
            ActionKey::CreateVisit => $this->stubAction($execution, $key, 'Visita registrada'),
        };
    }

    /**
     * @param  array<string, mixed>  $context
     */
    private function createNotification(
        AutomationExecutionModel $execution,
        AutomationActionModel $action,
        array $context,
    ): void {
        $config = $action->config ?? [];
        $title = (string) ($config['title'] ?? 'Notificação automática');
        $body = (string) ($config['body'] ?? 'Automação executada com sucesso.');

        $this->log($execution, LogLevel::Info, $title, [
            'type' => 'notification',
            'title' => $title,
            'body' => $body,
            'context' => $context,
        ]);
    }

    /**
     * @param  array<string, mixed>  $context
     */
    private function createTask(
        AutomationExecutionModel $execution,
        AutomationActionModel $action,
        array $context,
        ?User $actor,
    ): void {
        $dealId = (string) ($context['dealId'] ?? $context['deal_id'] ?? '');

        if ($dealId === '' || $actor === null) {
            $this->stubAction($execution, ActionKey::CreateTask, 'Tarefa registrada (sem oportunidade vinculada)');

            return;
        }

        $deal = DealModel::query()->find($dealId);

        if ($deal === null) {
            $this->log($execution, LogLevel::Warning, 'Oportunidade não encontrada para criar tarefa.', ['deal_id' => $dealId]);

            return;
        }

        $config = $action->config ?? [];

        try {
            $task = $this->createDealTask->execute($deal, $actor, [
                'type' => (string) ($config['type'] ?? DealTaskType::FollowUp->value),
                'title' => (string) ($config['title'] ?? 'Tarefa automática'),
                'description' => $config['description'] ?? null,
                'due_at' => $config['due_at'] ?? null,
                'is_automatic' => true,
                'set_as_next_action' => (bool) ($config['set_as_next_action'] ?? false),
            ]);

            $this->log($execution, LogLevel::Info, 'Tarefa criada na oportunidade.', [
                'task_id' => $task->id,
                'deal_id' => $dealId,
            ]);
        } catch (\Throwable $e) {
            $this->log($execution, LogLevel::Warning, 'Falha ao criar tarefa: '.$e->getMessage(), [
                'deal_id' => $dealId,
            ]);
        }
    }

    /**
     * @param  array<string, mixed>  $context
     */
    private function createReminder(
        AutomationExecutionModel $execution,
        AutomationActionModel $action,
        array $context,
        ?User $actor,
    ): void {
        $config = $action->config ?? [];
        $hours = (int) ($config['hours'] ?? 24);
        $dueAt = now()->addHours(max(1, $hours))->toDateTimeString();

        $dealId = (string) ($context['dealId'] ?? $context['deal_id'] ?? '');

        if ($dealId !== '' && $actor !== null) {
            $deal = DealModel::query()->find($dealId);
            if ($deal !== null) {
                try {
                    $task = $this->createDealTask->execute($deal, $actor, [
                        'type' => DealTaskType::FollowUp->value,
                        'title' => (string) ($config['title'] ?? 'Lembrete automático'),
                        'description' => $config['description'] ?? 'Lembrete criado pela automação.',
                        'due_at' => $dueAt,
                        'is_automatic' => true,
                        'set_as_next_action' => true,
                    ]);

                    $this->log($execution, LogLevel::Info, 'Lembrete criado como tarefa na oportunidade.', [
                        'task_id' => $task->id,
                        'due_at' => $dueAt,
                    ]);

                    return;
                } catch (\Throwable $e) {
                    $this->log($execution, LogLevel::Warning, 'Falha ao criar lembrete: '.$e->getMessage());
                }
            }
        }

        $this->log($execution, LogLevel::Info, (string) ($config['title'] ?? 'Lembrete registrado'), [
            'type' => 'reminder',
            'due_at' => $dueAt,
            'context' => $context,
        ]);
    }

    /**
     * @param  array<string, mixed>  $context
     */
    private function sendWhatsapp(
        AutomationExecutionModel $execution,
        AutomationActionModel $action,
        array $context,
    ): void {
        $config = $action->config ?? [];
        $requiresDelivery = (bool) ($config['require_delivery'] ?? false);

        try {
            $this->log($execution, LogLevel::Info, 'Mensagem WhatsApp enfileirada (simulado).', [
                'to' => $config['to'] ?? $context['phone'] ?? null,
                'template' => $config['template'] ?? null,
            ]);
        } catch (\Throwable $e) {
            $level = $requiresDelivery ? LogLevel::Error : LogLevel::Warning;
            $this->log($execution, $level, 'Falha ao enviar WhatsApp: '.$e->getMessage());
            if ($requiresDelivery) {
                throw $e;
            }
        }
    }

    /**
     * @param  array<string, mixed>  $context
     */
    private function sendEmail(
        AutomationExecutionModel $execution,
        AutomationActionModel $action,
        array $context,
    ): void {
        $config = $action->config ?? [];
        $requiresDelivery = (bool) ($config['require_delivery'] ?? false);

        try {
            $this->log($execution, LogLevel::Info, 'E-mail enfileirado (simulado).', [
                'to' => $config['to'] ?? $context['email'] ?? null,
                'subject' => $config['subject'] ?? 'Automação ImóvelZapAi',
            ]);
        } catch (\Throwable $e) {
            $level = $requiresDelivery ? LogLevel::Error : LogLevel::Warning;
            $this->log($execution, $level, 'Falha ao enviar e-mail: '.$e->getMessage());
            if ($requiresDelivery) {
                throw $e;
            }
        }
    }

    private function stubAction(AutomationExecutionModel $execution, ActionKey $key, string $message): void
    {
        $this->log($execution, LogLevel::Info, $message, [
            'action' => $key->value,
            'status' => 'ação registrada',
        ]);
    }

    /** @param  array<string, mixed>|null  $payload */
    private function log(
        AutomationExecutionModel $execution,
        LogLevel $level,
        string $message,
        ?array $payload = null,
    ): void {
        AutomationLogModel::query()->create([
            'tenant_id' => $execution->tenant_id,
            'execution_id' => $execution->id,
            'level' => $level,
            'message' => $message,
            'payload' => $payload,
            'created_at' => now(),
        ]);

        Log::info('[Automation] '.$message, ['execution_id' => $execution->id] + ($payload ?? []));
    }
}
