<?php

declare(strict_types=1);

namespace ImovelZapAi\Analytics\Infrastructure\Projectors;

use ImovelZapAi\Analytics\Application\Actions\RecordAnalyticsFactAction;
use ImovelZapAi\Analytics\Domain\Enums\AnalyticsEventKey;
use ImovelZapAi\Financial\Domain\Events\CommissionCalculated;
use ImovelZapAi\Financial\Domain\Events\PaymentReceived;
use ImovelZapAi\Financial\Infrastructure\Persistence\Eloquent\FinancialCommissionModel;
use ImovelZapAi\Financial\Infrastructure\Persistence\Eloquent\FinancialPaymentModel;
use ImovelZapAi\Sales\Domain\Events\DealCreated;
use ImovelZapAi\Sales\Domain\Events\DealStageChanged;
use ImovelZapAi\Sales\Domain\Events\DealWon;
use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;
use ImovelZapAi\Signatures\Domain\Events\SignatureCompleted;
use ImovelZapAi\Signatures\Domain\Events\SignatureRequested;
use ImovelZapAi\Visits\Domain\Events\VisitCompleted;
use ImovelZapAi\Visits\Domain\Events\VisitConfirmed;
use ImovelZapAi\Visits\Domain\Events\VisitCreated;
use ImovelZapAi\Visits\Infrastructure\Persistence\Eloquent\VisitModel;
use Illuminate\Support\Str;

final class ProjectDomainEventToAnalytics
{
    public function __construct(
        private readonly RecordAnalyticsFactAction $recordFact,
    ) {}

    public function fromDomainEvent(object $event): void
    {
        $eventKey = AnalyticsEventKey::tryFromEvent($event);
        if ($eventKey === null) {
            return;
        }

        [$tenantId, $entityType, $entityId, $userId, $amount, $meta] = $this->extractContext($event, $eventKey);

        if ($tenantId === '') {
            return;
        }

        $this->recordFact->execute(
            $tenantId,
            $eventKey,
            null,
            $entityType,
            $entityId,
            $userId,
            $amount,
            $meta,
        );
    }

    /** @return array{0: string, 1: ?string, 2: ?string, 3: ?int, 4: ?string, 5: array<string, mixed>} */
    private function extractContext(object $event, AnalyticsEventKey $eventKey): array
    {
        $meta = [];

        return match (true) {
            $event instanceof DealCreated => [
                $event->tenantId,
                'deal',
                $event->dealId,
                $this->dealUserId($event->dealId),
                null,
                $this->dealMeta($event->dealId),
            ],
            $event instanceof DealStageChanged => [
                $event->tenantId,
                'deal',
                $event->dealId,
                $this->dealUserId($event->dealId),
                null,
                [
                    'from_stage' => $event->fromStageKey,
                    'to_stage' => $event->toStageKey,
                ],
            ],
            $event instanceof DealWon => [
                $event->tenantId,
                'deal',
                $event->dealId,
                $this->dealUserId($event->dealId),
                $this->dealAmount($event->dealId),
                $this->dealMeta($event->dealId),
            ],
            $event instanceof VisitCreated,
            $event instanceof VisitConfirmed,
            $event instanceof VisitCompleted => [
                $event->tenantId,
                'visit',
                $event->visitId,
                $this->visitUserId($event->visitId),
                null,
                $this->visitMeta($event->visitId),
            ],
            $event instanceof SignatureRequested,
            $event instanceof SignatureCompleted => [
                $event->tenantId,
                'signature_request',
                $event->signatureRequestId,
                null,
                null,
                [],
            ],
            $event instanceof PaymentReceived => [
                $event->tenantId,
                'payment',
                $event->id,
                $this->paymentUserId($event->id),
                $this->paymentAmount($event->id),
                $this->paymentMeta($event->id),
            ],
            $event instanceof CommissionCalculated => [
                $event->tenantId,
                'commission',
                $event->id,
                $this->commissionUserId($event->id),
                $this->commissionAmount($event->id),
                [],
            ],
            default => $this->genericContext($event, $eventKey),
        };
    }

    /** @return array{0: string, 1: ?string, 2: ?string, 3: ?int, 4: ?string, 5: array<string, mixed>} */
    private function genericContext(object $event, AnalyticsEventKey $eventKey): array
    {
        $tenantId = property_exists($event, 'tenantId') ? (string) $event->tenantId : '';
        $entityId = null;

        foreach (['documentId', 'workflowId', 'executionId', 'requestedDocumentId', 'signatureRequestId', 'visitId', 'dealId'] as $prop) {
            if (property_exists($event, $prop)) {
                $entityId = (string) $event->{$prop};
                break;
            }
        }

        return [$tenantId, $eventKey->value, $entityId, null, null, []];
    }

    private function dealUserId(string $dealId): ?int
    {
        if (! Str::isUuid($dealId)) {
            return null;
        }

        return DealModel::query()->find($dealId)?->responsible_user_id;
    }

    /** @return array<string, mixed> */
    private function dealMeta(string $dealId): array
    {
        if (! Str::isUuid($dealId)) {
            return [];
        }

        $deal = DealModel::query()->find($dealId);
        if ($deal === null) {
            return [];
        }

        return array_filter([
            'amount' => $deal->amount,
        ], static fn ($v) => $v !== null);
    }

    private function dealAmount(string $dealId): ?string
    {
        if (! Str::isUuid($dealId)) {
            return null;
        }

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

        return $amount !== null ? (string) $amount : null;
    }

    private function visitUserId(string $visitId): ?int
    {
        if (! Str::isUuid($visitId)) {
            return null;
        }

        return VisitModel::query()->find($visitId)?->responsible_user_id;
    }

    /** @return array<string, mixed> */
    private function visitMeta(string $visitId): array
    {
        if (! Str::isUuid($visitId)) {
            return [];
        }

        return VisitModel::query()->find($visitId) !== null
            ? ['source' => 'whatsapp']
            : [];
    }

    private function paymentUserId(string $paymentId): ?int
    {
        if (! Str::isUuid($paymentId)) {
            return null;
        }

        return FinancialPaymentModel::query()->find($paymentId)?->created_by;
    }

    private function paymentAmount(string $paymentId): ?string
    {
        if (! Str::isUuid($paymentId)) {
            return null;
        }

        $amount = FinancialPaymentModel::query()->find($paymentId)?->amount;

        return $amount !== null ? (string) $amount : null;
    }

    /** @return array<string, mixed> */
    private function paymentMeta(string $paymentId): array
    {
        if (! Str::isUuid($paymentId)) {
            return [];
        }

        $payment = FinancialPaymentModel::query()->find($paymentId);

        return $payment ? ['amount' => $payment->amount] : [];
    }

    private function commissionUserId(string $commissionId): ?int
    {
        if (! Str::isUuid($commissionId)) {
            return null;
        }

        $commission = FinancialCommissionModel::query()->with('deal')->find($commissionId);

        return $commission?->deal?->responsible_user_id;
    }

    private function commissionAmount(string $commissionId): ?string
    {
        if (! Str::isUuid($commissionId)) {
            return null;
        }

        $amount = FinancialCommissionModel::query()->find($commissionId)?->total_amount;

        return $amount !== null ? (string) $amount : null;
    }
}
