<?php

declare(strict_types=1);

namespace ImovelZapAi\Signatures\Application\Actions;

use App\Models\User;
use Illuminate\Support\Facades\DB;
use ImovelZapAi\Signatures\Application\Services\SignatureAccessTokenService;
use ImovelZapAi\Signatures\Application\Services\SignatureAuditWriter;
use ImovelZapAi\Signatures\Application\Services\SignatureProviderRegistry;
use ImovelZapAi\Signatures\Application\Services\SignatureStatusSynchronizer;
use ImovelZapAi\Signatures\Domain\Enums\SignatureAuditEvent;
use ImovelZapAi\Signatures\Domain\Enums\SignatureRequestStatus;
use ImovelZapAi\Signatures\Domain\Events\SignatureRequested;
use ImovelZapAi\Signatures\Domain\Exceptions\SignatureException;
use ImovelZapAi\Signatures\Infrastructure\Persistence\Eloquent\SignatureReminderModel;
use ImovelZapAi\Signatures\Infrastructure\Persistence\Eloquent\SignatureRequestModel;

final class SendSignatureRequestAction
{
    public function __construct(
        private readonly SignatureAccessTokenService $tokens,
        private readonly SignatureProviderRegistry $providers,
        private readonly SignatureAuditWriter $audit,
        private readonly SignatureStatusSynchronizer $sync,
    ) {}

    public function execute(SignatureRequestModel $request, User $actor): SignatureRequestModel
    {
        if (! in_array($request->status, [SignatureRequestStatus::Draft, SignatureRequestStatus::InReview], true)) {
            throw SignatureException::invalidState('somente rascunhos podem ser enviados.');
        }

        return DB::transaction(function () use ($request, $actor): SignatureRequestModel {
            $request->load('signers');

            $signerUrls = [];
            $signerPlains = [];
            foreach ($request->signers as $signer) {
                $issued = $this->tokens->issueForSigner($signer);
                $signerUrls[$signer->id] = $issued['url'];
                $signerPlains[$signer->id] = $issued['plain'];
            }

            $meta = $request->meta ?? [];
            $meta['signer_urls'] = $signerUrls;
            if (app()->environment('testing')) {
                $meta['signer_plains'] = $signerPlains;
            }
            $request->forceFill(['meta' => $meta])->save();

            $provider = $this->providers->get($request->provider);
            $provider->send($request->fresh(['signers', 'deal.conversation', 'document.contact']));

            $request->forceFill([
                'status' => SignatureRequestStatus::AwaitingSignatures,
                'sent_at' => now(),
            ])->save();

            $hours = (array) config('signatures.reminder_hours', [24, 72]);
            foreach ($request->signers as $signer) {
                foreach ($hours as $hour) {
                    SignatureReminderModel::query()->create([
                        'tenant_id' => $request->tenant_id,
                        'signature_request_id' => $request->id,
                        'signer_id' => $signer->id,
                        'channel' => 'whatsapp',
                        'scheduled_at' => now()->addHours((int) $hour),
                        'status' => 'pending',
                    ]);
                }
            }

            $this->audit->write(
                $request->tenant_id,
                $request->id,
                SignatureAuditEvent::Sent,
                actorType: 'broker',
                actorUserId: (int) $actor->id,
                payload: ['signer_urls' => $signerUrls],
                message: 'Solicitação de assinatura enviada.',
            );

            SignatureRequested::dispatch($request->tenant_id, $request->id);

            $this->sync->sync($request);

            return $request->fresh(['signers', 'steps', 'document', 'reminders']);
        });
    }
}
