<?php

declare(strict_types=1);

namespace ImovelZapAi\Billing\Application\Actions;

use ImovelZapAi\Billing\Application\Contracts\MercadoPagoClient;
use ImovelZapAi\Billing\Infrastructure\Persistence\Eloquent\BillingPaymentEventModel;
use ImovelZapAi\Organizations\Domain\Enums\SubscriptionStatus;
use ImovelZapAi\Organizations\Infrastructure\Persistence\Eloquent\OrganizationSubscriptionModel;

final class SyncSubscriptionFromWebhookAction
{
    public function __construct(
        private readonly MercadoPagoClient $client,
    ) {}

    /**
     * @param  array<string, mixed>  $payload
     */
    public function execute(array $payload): ?OrganizationSubscriptionModel
    {
        $externalId = $this->extractPreapprovalId($payload);
        $eventType = (string) ($payload['type'] ?? $payload['action'] ?? 'unknown');

        $subscription = null;
        if ($externalId !== null) {
            $subscription = OrganizationSubscriptionModel::query()
                ->where('mp_preapproval_id', $externalId)
                ->first();

            if ($subscription === null) {
                $remote = $this->client->getPreapproval($externalId);
                $ref = $remote['external_reference'] ?? null;
                if (is_string($ref) && $ref !== '') {
                    $subscription = OrganizationSubscriptionModel::query()->find($ref);
                }
            }

            if ($subscription !== null) {
                $remote = $this->client->getPreapproval($externalId);
                $status = $this->mapStatus((string) ($remote['status'] ?? ''));

                $subscription->forceFill([
                    'mp_preapproval_id' => $externalId,
                    'status' => $status,
                    'canceled_at' => $status === SubscriptionStatus::Canceled ? now() : null,
                    'grace_ends_at' => $status === SubscriptionStatus::PastDue
                        ? now()->addDays((int) config('billing.grace_days', 3))
                        : null,
                    'current_period_ends_at' => $status === SubscriptionStatus::Active
                        ? ((string) ($subscription->billing_cycle ?? 'monthly') === 'yearly' ? now()->addYear() : now()->addMonth())
                        : $subscription->current_period_ends_at,
                ])->save();
            }
        }

        BillingPaymentEventModel::query()->create([
            'tenant_id' => $subscription?->tenant_id,
            'organization_subscription_id' => $subscription?->id,
            'provider' => 'mercadopago',
            'event_type' => $eventType,
            'external_id' => $externalId,
            'status' => $subscription?->status?->value,
            'payload' => $payload,
        ]);

        return $subscription?->fresh(['plan']);
    }

    /**
     * @param  array<string, mixed>  $payload
     */
    private function extractPreapprovalId(array $payload): ?string
    {
        $dataId = $payload['data']['id'] ?? $payload['id'] ?? null;
        if (is_string($dataId) || is_numeric($dataId)) {
            return (string) $dataId;
        }

        return null;
    }

    private function mapStatus(string $mpStatus): SubscriptionStatus
    {
        return match (strtolower($mpStatus)) {
            'authorized', 'active' => SubscriptionStatus::Active,
            'pending' => SubscriptionStatus::Trialing,
            'paused' => SubscriptionStatus::PastDue,
            'cancelled', 'canceled' => SubscriptionStatus::Canceled,
            default => SubscriptionStatus::PastDue,
        };
    }
}
