<?php

declare(strict_types=1);

namespace ImovelZapAi\ClientPortal\Application\Actions;

use App\Models\User;
use Illuminate\Support\Facades\DB;
use ImovelZapAi\ClientPortal\Application\Services\PortalActivityWriter;
use ImovelZapAi\ClientPortal\Application\Services\PortalProgressCalculator;
use ImovelZapAi\ClientPortal\Application\Services\PortalTokenService;
use ImovelZapAi\ClientPortal\Domain\Enums\PortalActivityEvent;
use ImovelZapAi\ClientPortal\Domain\Enums\PortalStatus;
use ImovelZapAi\ClientPortal\Domain\Enums\RequestedDocumentStatus;
use ImovelZapAi\ClientPortal\Domain\Events\ClientPortalCreated;
use ImovelZapAi\ClientPortal\Domain\Exceptions\ClientPortalException;
use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\ClientPortalModel;
use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\DocumentRequestModel;
use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\RequestedDocumentModel;
use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\ContactModel;
use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;

final class CreateClientPortalAction
{
    public function __construct(
        private readonly PortalTokenService $tokens,
        private readonly PortalActivityWriter $activity,
        private readonly PortalProgressCalculator $progress,
    ) {}

    /**
     * @param  array{
     *     contact_id: string,
     *     document_keys: list<string>,
     *     deal_id?: string|null,
     *     conversation_id?: string|null,
     *     owner_id?: string|null,
     *     title?: string|null,
     *     greeting_name?: string|null,
     *     intro_message?: string|null,
     *     expires_at?: string|null,
     *     responsible_user_id?: int|null,
     * }  $data
     * @return array{portal: ClientPortalModel, plain_token: string, url: string}
     */
    public function execute(string $tenantId, User $actor, array $data): array
    {
        $keys = array_values(array_unique($data['document_keys'] ?? []));
        if ($keys === []) {
            throw ClientPortalException::invalidState('selecione ao menos um documento.');
        }

        $catalog = collect(config('client_portal.document_catalog', []))
            ->keyBy('key');

        return DB::transaction(function () use ($tenantId, $actor, $data, $keys, $catalog): array {
            $contact = ContactModel::query()
                ->where('tenant_id', $tenantId)
                ->whereKey($data['contact_id'])
                ->firstOrFail();

            $dealId = $data['deal_id'] ?? null;
            if ($dealId !== null) {
                DealModel::query()->where('tenant_id', $tenantId)->whereKey($dealId)->firstOrFail();
            }

            $greeting = $data['greeting_name']
                ?? $contact->display_name
                ?? 'cliente';

            $portal = ClientPortalModel::query()->create([
                'tenant_id' => $tenantId,
                'contact_id' => $contact->id,
                'deal_id' => $dealId,
                'conversation_id' => $data['conversation_id'] ?? null,
                'owner_id' => $data['owner_id'] ?? null,
                'created_by' => $actor->id,
                'responsible_user_id' => $data['responsible_user_id'] ?? $actor->id,
                'title' => $data['title'] ?? ('Documentos — '.$greeting),
                'greeting_name' => $greeting,
                'status' => PortalStatus::Active,
                'intro_message' => $data['intro_message']
                    ?? 'Para continuarmos sua negociação, envie os documentos abaixo.',
                'expires_at' => isset($data['expires_at'])
                    ? $data['expires_at']
                    : now()->addDays((int) config('client_portal.token_ttl_days', 14)),
                'last_activity_at' => now(),
                'documents_total' => count($keys),
            ]);

            $request = DocumentRequestModel::query()->create([
                'tenant_id' => $tenantId,
                'client_portal_id' => $portal->id,
                'status' => 'open',
            ]);

            $position = 1;
            foreach ($keys as $key) {
                $item = $catalog->get($key);
                RequestedDocumentModel::query()->create([
                    'tenant_id' => $tenantId,
                    'client_portal_id' => $portal->id,
                    'document_request_id' => $request->id,
                    'document_type_key' => $key,
                    'label' => $item['label'] ?? strtoupper($key),
                    'position' => $position++,
                    'is_required' => true,
                    'status' => RequestedDocumentStatus::Pending,
                ]);
            }

            $issued = $this->tokens->issue($portal, $portal->expires_at);

            $this->activity->write(
                $tenantId,
                $portal->id,
                PortalActivityEvent::PortalCreated,
                actorType: 'broker',
                actorUserId: (int) $actor->id,
                message: 'Portal de documentos criado.',
            );

            $this->progress->refresh($portal);
            ClientPortalCreated::dispatch($tenantId, $portal->id);

            return [
                'portal' => $portal->fresh(['requestedDocuments', 'contact', 'deal']),
                'plain_token' => $issued['plain'],
                'url' => $issued['url'],
            ];
        });
    }
}
