<?php

declare(strict_types=1);

namespace App\Services\Billing;

use App\Models\Plan;
use App\Models\User;
use Illuminate\Support\Facades\Log;
use Srmklive\PayPal\Services\PayPal as PayPalClient;

class PayPalBillingService implements BillingServiceInterface
{
    private PayPalClient $client;

    public function __construct()
    {
        $this->client = new PayPalClient;
        $this->client->setApiCredentials(config('paypal'));
        $this->client->getAccessToken();
    }

    /**
     * Note: $billingCycle is accepted for interface compatibility but is not used here.
     * PayPal subscription billing frequency is configured on the PayPal plan itself,
     * not at subscription creation time. Each billing cycle requires a separate PayPal plan.
     */
    public function createSubscription(User $user, Plan $plan, ?string $paymentMethodId = null, ?string $couponCode = null, string $billingCycle = 'monthly'): array
    {
        if ($billingCycle !== 'monthly') {
            Log::warning('PayPal subscription created with non-monthly billing cycle — PayPal plan may not match', [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'billing_cycle' => $billingCycle,
            ]);
        }

        if (! $plan->paypal_plan_id) {
            throw new \RuntimeException('Plan does not have a PayPal plan ID configured.');
        }

        try {
            $response = $this->client->createSubscription([
                'plan_id' => $plan->paypal_plan_id,
                'subscriber' => [
                    'name' => [
                        'given_name' => $user->name,
                    ],
                    'email_address' => $user->email,
                ],
                'application_context' => [
                    'brand_name' => config('app.name'),
                    'return_url' => route('account.billing.paypal.callback', ['plan' => $plan->id]),
                    'cancel_url' => route('account.billing.paypal.cancel'),
                    'user_action' => 'SUBSCRIBE_NOW',
                ],
            ]);

            if (isset($response['id'])) {
                $approvalUrl = collect($response['links'] ?? [])
                    ->firstWhere('rel', 'approve')['href'] ?? null;

                return [
                    'subscription_id' => $response['id'],
                    'status' => $response['status'] ?? 'APPROVAL_PENDING',
                    'approval_url' => $approvalUrl,
                ];
            }

            throw new \RuntimeException('Failed to create PayPal subscription: '.json_encode($response));
        } catch (\Exception $e) {
            Log::error('PayPal subscription creation failed', [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'error' => $e->getMessage(),
            ]);

            throw $e;
        }
    }

    public function cancelSubscription(User $user, string $subscriptionId, bool $immediately = false): bool
    {
        try {
            $this->client->cancelSubscription($subscriptionId, 'Customer requested cancellation');

            return true;
        } catch (\Exception $e) {
            Log::error('PayPal subscription cancellation failed', [
                'subscription_id' => $subscriptionId,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    public function swapSubscription(User $user, string $subscriptionId, Plan $newPlan, string $billingCycle = 'monthly'): array
    {
        try {
            $response = $this->client->reviseSubscription($subscriptionId, [
                'plan_id' => $newPlan->paypal_plan_id,
            ]);

            $approvalUrl = collect($response['links'] ?? [])
                ->firstWhere('rel', 'approve')['href'] ?? null;

            return [
                'subscription_id' => $subscriptionId,
                'status' => $response['status'] ?? 'APPROVAL_PENDING',
                'approval_url' => $approvalUrl,
            ];
        } catch (\Exception $e) {
            Log::error('PayPal subscription swap failed', [
                'subscription_id' => $subscriptionId,
                'error' => $e->getMessage(),
            ]);

            throw $e;
        }
    }

    public function resumeSubscription(User $user, string $subscriptionId): bool
    {
        try {
            $this->client->activateSubscription($subscriptionId, 'Customer requested reactivation');

            return true;
        } catch (\Exception $e) {
            Log::error('PayPal subscription resume failed', [
                'subscription_id' => $subscriptionId,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    public function addPaymentMethod(User $user, string $paymentMethodId): bool
    {
        // PayPal handles payment methods through its own flow
        return true;
    }

    public function removePaymentMethod(User $user, string $paymentMethodId): bool
    {
        // PayPal handles payment methods through its own flow
        return true;
    }

    public function setDefaultPaymentMethod(User $user, string $paymentMethodId): bool
    {
        // PayPal handles payment methods through its own flow
        return true;
    }

    /** @return array<int, array{id: string, brand: string, last_four: string, exp_month: int, exp_year: int, is_default: bool}> */
    public function getPaymentMethods(User $user): array
    {
        // PayPal manages payment methods externally
        return [];
    }

    public function getGateway(): string
    {
        return 'paypal';
    }
}
