<?php

namespace App\Services\Billing;

use App\Models\Order;
use App\Models\Payment;
use App\Models\Subscription;
use App\Models\User;
use App\Models\UserApiKey;
use App\Services\Keywords\KeywordQuotaService;

class PaypalWebhookProcessor
{
    public function __construct(
        private readonly SubscriptionTransitionService $subscriptionTransition,
        private readonly KeywordQuotaService $keywordQuota
    ) {}

    /**
     * @param  array<string,mixed>  $payload
     */
    public function process(string $eventType, array $payload): void
    {
        $resource = $payload['resource'] ?? [];
        if (! is_array($resource)) {
            return;
        }

        $subscriptionId = (string) ($resource['id'] ?? '');
        $email = (string) ($resource['subscriber']['email_address'] ?? '');

        if ($subscriptionId === '' || $email === '') {
            return;
        }

        $user = User::where('email', $email)->first();
        if (! $user) {
            throw new \RuntimeException('User not found for webhook email.');
        }

        if ($eventType === 'BILLING.SUBSCRIPTION.ACTIVATED') {
            $order = Order::query()
                ->where('provider', 'paypal')
                ->where('provider_ref', $subscriptionId)
                ->latest('id')
                ->first();
            $planCode = (string) ($order?->plan_code ?: 'personal_monthly');

            Subscription::updateOrCreate([
                'provider' => 'paypal',
                'provider_ref' => $subscriptionId,
            ], [
                'user_id' => $user->id,
                'plan' => $planCode,
                'status' => 'active',
                'started_at' => now(),
                'expires_at' => null,
                'canceled_at' => null,
            ]);
            Order::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->update(['status' => 'paid']);
            Payment::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->update(['status' => 'paid']);
            $user->update(['tier' => 'personal']);
            $this->keywordQuota->enforceForUser((int) $user->id, 'personal');
            $this->subscriptionTransition->settleForActivatedPlan(
                (int) $user->id,
                'paypal',
                $subscriptionId,
                $planCode
            );

            return;
        }

        if ($eventType === 'BILLING.SUBSCRIPTION.CANCELLED' || $eventType === 'BILLING.SUBSCRIPTION.SUSPENDED') {
            Subscription::where('user_id', $user->id)
                ->where('provider', 'paypal')
                ->where('provider_ref', $subscriptionId)
                ->where('status', 'active')
                ->update([
                    'status' => $eventType === 'BILLING.SUBSCRIPTION.CANCELLED' ? 'canceled' : 'suspended',
                    'expires_at' => now(),
                ]);

            $this->syncUserTier($user->id);
        }
    }

    private function syncUserTier(int $userId): void
    {
        $active = Subscription::where('user_id', $userId)
            ->where('status', 'active')
            ->where(function ($q): void {
                $q->whereNull('expires_at')
                    ->orWhere('expires_at', '>', now());
            })
            ->exists();

        User::where('id', $userId)->update([
            'tier' => $active ? 'personal' : 'free',
        ]);
        $this->keywordQuota->enforceForUser($userId, $active ? 'personal' : 'free');
        if (! $active) {
            UserApiKey::where('user_id', $userId)->update(['revoked_at' => now()]);
        }
    }
}
