<?php

declare(strict_types=1);

namespace ImovelZapAi\Signatures\Application\Actions;

use ImovelZapAi\Signatures\Application\Services\SignatureAccessTokenService;
use ImovelZapAi\Signatures\Application\Services\SignatureAuditWriter;
use ImovelZapAi\Signatures\Application\Services\SignatureStatusSynchronizer;
use ImovelZapAi\Signatures\Domain\Enums\SignatureAuditEvent;
use ImovelZapAi\Signatures\Domain\Enums\SignerStatus;
use ImovelZapAi\Signatures\Domain\Events\SignatureViewed;
use ImovelZapAi\Signatures\Infrastructure\Persistence\Eloquent\SignatureAuditModel;
use ImovelZapAi\Signatures\Infrastructure\Persistence\Eloquent\SignatureRequestModel;
use ImovelZapAi\Signatures\Infrastructure\Persistence\Eloquent\SignatureStepModel;
use ImovelZapAi\Signatures\Infrastructure\Persistence\Eloquent\SignerModel;

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

    /** @return array{request: SignatureRequestModel, signer: SignerModel} */
    public function execute(string $plainToken, ?string $ip = null, ?string $userAgent = null): array
    {
        $resolved = $this->tokens->resolve($plainToken);
        $signer = $resolved['signer'];
        $request = $resolved['request'];

        if (in_array($signer->status, [SignerStatus::Pending, SignerStatus::Notified], true)) {
            $signer->forceFill([
                'status' => SignerStatus::Viewed,
                'viewed_at' => now(),
            ])->save();
        } elseif ($signer->viewed_at === null) {
            $signer->forceFill(['viewed_at' => now()])->save();
        }

        SignatureStepModel::query()
            ->where('signature_request_id', $request->id)
            ->where('order_index', $signer->order)
            ->whereNull('opened_at')
            ->update(['opened_at' => now(), 'status' => 'opened']);

        $recent = SignatureAuditModel::query()
            ->where('signature_request_id', $request->id)
            ->where('signer_id', $signer->id)
            ->where('event', SignatureAuditEvent::Viewed)
            ->where('created_at', '>=', now()->subHour())
            ->exists();

        if (! $recent) {
            $this->audit->write(
                $request->tenant_id,
                $request->id,
                SignatureAuditEvent::Viewed,
                actorType: 'signer',
                signerId: $signer->id,
                payload: ['ip' => $ip, 'user_agent' => $userAgent ? substr($userAgent, 0, 512) : null],
                message: 'Signatário visualizou o documento.',
            );
            SignatureViewed::dispatch($request->tenant_id, $request->id);
        }

        $this->sync->sync($request->fresh(['signers']));

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