<?php

declare(strict_types=1);

namespace ImovelZapAi\Sales\Application\Actions;

use App\Models\User;
use Illuminate\Support\Facades\DB;
use ImovelZapAi\Sales\Application\Services\DealActivityRecorder;
use ImovelZapAi\Sales\Application\Services\DealHistoryWriter;
use ImovelZapAi\Sales\Domain\Enums\DealActivityType;
use ImovelZapAi\Sales\Domain\Enums\DealHistoryEvent;
use ImovelZapAi\Sales\Domain\Enums\DealPriority;
use ImovelZapAi\Sales\Domain\Enums\DealTaskStatus;
use ImovelZapAi\Sales\Domain\Enums\DealTaskType;
use ImovelZapAi\Sales\Domain\Events\DealTaskCreated;
use ImovelZapAi\Sales\Domain\Exceptions\DealException;
use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;
use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealTaskModel;

final class CreateDealTaskAction
{
    public function __construct(
        private readonly DealActivityRecorder $activities,
        private readonly DealHistoryWriter $history,
    ) {}

    /**
     * @param  array{
     *     type: string,
     *     title: string,
     *     description?: string|null,
     *     due_at?: string|null,
     *     priority?: string|null,
     *     responsible_user_id?: int|null,
     *     is_automatic?: bool,
     *     set_as_next_action?: bool,
     * }  $data
     */
    public function execute(DealModel $deal, User $actor, array $data): DealTaskModel
    {
        if ($deal->isClosed() && ! (bool) ($data['is_automatic'] ?? false)) {
            throw DealException::alreadyClosed();
        }

        return DB::transaction(function () use ($deal, $actor, $data): DealTaskModel {
            $type = DealTaskType::from($data['type']);
            $task = DealTaskModel::query()->create([
                'tenant_id' => $deal->tenant_id,
                'deal_id' => $deal->id,
                'responsible_user_id' => $data['responsible_user_id'] ?? $deal->responsible_user_id ?? $actor->id,
                'created_by' => $actor->id,
                'type' => $type,
                'priority' => DealPriority::tryFrom((string) ($data['priority'] ?? 'medium')) ?? DealPriority::Medium,
                'status' => DealTaskStatus::Open,
                'title' => $data['title'],
                'description' => $data['description'] ?? null,
                'due_at' => $data['due_at'] ?? null,
                'is_automatic' => (bool) ($data['is_automatic'] ?? false),
            ]);

            $this->activities->record(
                $deal,
                DealActivityType::TaskCreated,
                $task->title,
                $task->description,
                (int) $actor->id,
                ['task_id' => $task->id, 'type' => $type->value],
            );

            $this->history->write(
                $deal->tenant_id,
                $deal->id,
                DealHistoryEvent::TaskCreated,
                actorUserId: (int) $actor->id,
                after: ['task_id' => $task->id],
                message: $task->title,
            );

            if (($data['set_as_next_action'] ?? true) === true) {
                $deal->forceFill([
                    'next_action_at' => $task->due_at,
                    'next_action_type' => $type,
                    'next_action_notes' => $task->title,
                ])->save();

                $this->activities->record(
                    $deal,
                    DealActivityType::NextActionSet,
                    'Próxima ação: '.$task->title,
                    actorUserId: (int) $actor->id,
                );
            }

            DealTaskCreated::dispatch($deal->tenant_id, $deal->id, $task->id);

            return $task->fresh();
        });
    }
}
