<?php

namespace App\Services\Billing;

use App\Models\Order;
use App\Models\Payment;
use App\Models\Subscription;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class SubscriptionTransitionService
{
    /**
     * Cancel all pending checkout state for a user across providers.
     */
    public function cancelPendingForUser(int $userId): void
    {
        Subscription::query()
            ->where('user_id', $userId)
            ->where('status', 'pending')
            ->update([
                'status' => 'canceled',
                'canceled_at' => now(),
            ]);

        Order::query()
            ->where('user_id', $userId)
            ->where('status', 'pending')
            ->update(['status' => 'canceled']);

        Payment::query()
            ->where('user_id', $userId)
            ->where('status', 'pending')
            ->update(['status' => 'canceled']);
    }

    /**
     * Cancel other active/pending subscriptions when a new plan has been activated.
     */
    public function settleForActivatedPlan(
        int $userId,
        string $activeProvider,
        string $activeProviderRef,
        string $newPlanCode
    ): void {
        $others = Subscription::query()
            ->where('user_id', $userId)
            ->whereIn('status', ['active', 'pending'])
            ->where(function ($query) use ($activeProvider, $activeProviderRef) {
                $query->where('provider', '!=', $activeProvider)
                    ->orWhere('provider_ref', '!=', $activeProviderRef);
            })
            ->get();

        if ($others->isEmpty()) {
            return;
        }

        $mode = $this->resolvePaypalMode((string) config('dewemoji.billing.mode', 'sandbox'));
        foreach ($others as $sub) {
            if ((string) $sub->plan === 'personal_lifetime') {
                // Never auto-cancel lifetime ownership on later recurring checkouts.
                continue;
            }

            if ($sub->status === 'pending') {
                $sub->status = 'canceled';
                $sub->canceled_at = now();
                $sub->save();

                continue;
            }

            // Lifetime is one-time ownership; cancel any recurring subscription.
            $isRecurring = in_array((string) $sub->plan, ['personal_monthly', 'personal_annual'], true);
            if ($sub->provider === 'paypal' && $isRecurring && $sub->provider_ref) {
                $cancelled = $this->cancelPaypalSubscription($mode, (string) $sub->provider_ref);
                if (! $cancelled) {
                    Log::warning('Could not cancel previous PayPal subscription during plan transition', [
                        'user_id' => $userId,
                        'new_plan' => $newPlanCode,
                        'old_subscription_id' => $sub->provider_ref,
                    ]);

                    continue;
                }
            }

            $sub->status = 'canceled';
            $sub->canceled_at = now();
            $sub->save();
        }
    }

    private function cancelPaypalSubscription(string $mode, string $subscriptionId): bool
    {
        $token = $this->getAccessToken($mode);
        if (! $token) {
            return false;
        }

        $apiBase = (string) config("dewemoji.billing.providers.paypal.{$mode}.api_base");
        if ($apiBase === '') {
            return false;
        }

        $res = Http::withToken($token)
            ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10))
            ->post(rtrim($apiBase, '/')."/v1/billing/subscriptions/{$subscriptionId}/cancel", [
                'reason' => 'Switched plan in Dewemoji',
            ]);

        // PayPal may return 204 on success, and 404 if already cancelled/not found.
        return in_array($res->status(), [200, 204, 404], true);
    }

    private function getAccessToken(string $mode): ?string
    {
        $clientId = config("dewemoji.billing.providers.paypal.{$mode}.client_id");
        $clientSecret = config("dewemoji.billing.providers.paypal.{$mode}.client_secret");
        $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base");

        if (! $clientId || ! $clientSecret || ! $apiBase) {
            return null;
        }

        $res = Http::asForm()
            ->withBasicAuth($clientId, $clientSecret)
            ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10))
            ->post(rtrim((string) $apiBase, '/').'/v1/oauth2/token', [
                'grant_type' => 'client_credentials',
            ]);

        if (! $res->successful()) {
            return null;
        }

        return $res->json('access_token');
    }

    private function paypalConfigured(string $mode): bool
    {
        $enabled = (bool) config('dewemoji.billing.providers.paypal.enabled', false);
        $clientId = config("dewemoji.billing.providers.paypal.{$mode}.client_id");
        $clientSecret = config("dewemoji.billing.providers.paypal.{$mode}.client_secret");
        $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base");

        return $enabled && $clientId && $clientSecret && $apiBase;
    }

    private function resolvePaypalMode(string $preferred): string
    {
        if ($this->paypalConfigured($preferred)) {
            return $preferred;
        }

        $fallback = $preferred === 'live' ? 'sandbox' : 'live';
        if ($this->paypalConfigured($fallback)) {
            return $fallback;
        }

        return $preferred;
    }
}
