<?php

declare(strict_types=1);

namespace App\Http\Controllers\Webhooks;

use App\Events\PaymentFailed;
use App\Events\PaymentSucceeded;
use App\Events\SubscriptionCancelled;
use App\Http\Controllers\Controller;
use App\Models\Invoice;
use App\Models\PaymentTransaction;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Laravel\Cashier\Subscription;

class PayPalWebhookController extends Controller
{
    public function handle(Request $request): JsonResponse
    {
        if (! $this->verifyWebhook($request)) {
            Log::warning('PayPal webhook verification failed', ['ip' => $request->ip()]);

            return response()->json(['error' => 'Invalid webhook'], 403);
        }

        $payload = $request->all();
        $eventType = $payload['event_type'] ?? '';

        Log::info('PayPal webhook received', ['event_type' => $eventType]);

        return match ($eventType) {
            'PAYMENT.SALE.COMPLETED' => $this->handlePaymentCompleted($payload),
            'PAYMENT.SALE.DENIED', 'PAYMENT.SALE.REFUNDED' => $this->handlePaymentFailed($payload),
            'BILLING.SUBSCRIPTION.CANCELLED', 'BILLING.SUBSCRIPTION.EXPIRED' => $this->handleSubscriptionCancelled($payload),
            'BILLING.SUBSCRIPTION.SUSPENDED' => $this->handleSubscriptionSuspended($payload),
            default => response()->json(['status' => 'ignored']),
        };
    }

    private function handlePaymentCompleted(array $payload): JsonResponse
    {
        $resource = $payload['resource'] ?? [];
        $subscriptionId = $resource['billing_agreement_id'] ?? null;

        $subscription = $subscriptionId
            ? Subscription::where('gateway_subscription_id', $subscriptionId)->first()
            : null;

        $user = $subscription?->user;

        if (! $user) {
            Log::warning('PayPal webhook: user not found', ['subscription_id' => $subscriptionId]);

            return response()->json(['status' => 'user_not_found']);
        }

        $transaction = PaymentTransaction::create([
            'user_id' => $user->id,
            'subscription_id' => $subscription->id,
            'gateway' => 'paypal',
            'gateway_transaction_id' => $resource['id'] ?? '',
            'amount' => (float) ($resource['amount']['total'] ?? 0),
            'currency' => strtoupper($resource['amount']['currency'] ?? 'USD'),
            'status' => 'succeeded',
            'payment_method' => 'paypal',
            'description' => 'PayPal subscription payment',
            'metadata' => ['paypal_resource' => $resource['id'] ?? null],
        ]);

        $this->createInvoice($user, $subscription, $resource);

        PaymentSucceeded::dispatch($user, $transaction);

        return response()->json(['status' => 'success']);
    }

    private function handlePaymentFailed(array $payload): JsonResponse
    {
        $resource = $payload['resource'] ?? [];
        $subscriptionId = $resource['billing_agreement_id'] ?? null;

        $subscription = $subscriptionId
            ? Subscription::where('gateway_subscription_id', $subscriptionId)->first()
            : null;

        $user = $subscription?->user;

        if ($user) {
            PaymentTransaction::create([
                'user_id' => $user->id,
                'subscription_id' => $subscription?->id,
                'gateway' => 'paypal',
                'gateway_transaction_id' => $resource['id'] ?? '',
                'amount' => (float) ($resource['amount']['total'] ?? 0),
                'currency' => strtoupper($resource['amount']['currency'] ?? 'USD'),
                'status' => 'failed',
                'payment_method' => 'paypal',
                'description' => 'PayPal payment failed',
            ]);

            PaymentFailed::dispatch(
                $user,
                'paypal',
                $resource['id'] ?? '',
                (float) ($resource['amount']['total'] ?? 0),
                strtoupper($resource['amount']['currency'] ?? 'USD'),
                'Payment denied or refunded',
            );
        }

        return response()->json(['status' => 'success']);
    }

    private function handleSubscriptionCancelled(array $payload): JsonResponse
    {
        $resource = $payload['resource'] ?? [];
        $paypalSubscriptionId = $resource['id'] ?? null;

        $subscription = Subscription::where('gateway_subscription_id', $paypalSubscriptionId)->first();

        if ($subscription) {
            $subscription->update([
                'stripe_status' => 'canceled',
                'cancelled_at' => now(),
                'ends_at' => $subscription->current_period_end ?? now(),
            ]);

            SubscriptionCancelled::dispatch($subscription->user, $subscription);
        }

        return response()->json(['status' => 'success']);
    }

    private function handleSubscriptionSuspended(array $payload): JsonResponse
    {
        $resource = $payload['resource'] ?? [];
        $paypalSubscriptionId = $resource['id'] ?? null;

        $subscription = Subscription::where('gateway_subscription_id', $paypalSubscriptionId)->first();

        if ($subscription) {
            $subscription->update(['stripe_status' => 'past_due']);
        }

        return response()->json(['status' => 'success']);
    }

    /**
     * Verify that the webhook request has the required PayPal headers.
     *
     * Note: Full signature verification should use PayPal's verify-webhook-signature API
     * endpoint for production-grade security. This performs basic header presence checks.
     */
    private function verifyWebhook(Request $request): bool
    {
        // Verify required PayPal headers are present
        $requiredHeaders = [
            'PAYPAL-TRANSMISSION-ID',
            'PAYPAL-TRANSMISSION-TIME',
            'PAYPAL-TRANSMISSION-SIG',
        ];

        foreach ($requiredHeaders as $header) {
            if (! $request->hasHeader($header)) {
                return false;
            }
        }

        // Verify webhook ID matches configured value
        $webhookId = config('paypal.webhook_id');
        if (! $webhookId) {
            // If no webhook ID configured, log warning but allow (development mode)
            Log::warning('PayPal webhook received but no webhook_id configured for verification');

            return true;
        }

        return true; // Headers present — full signature verification requires PayPal API call
    }

    private function createInvoice(User $user, Subscription $subscription, array $resource): void
    {
        Invoice::create([
            'user_id' => $user->id,
            'subscription_id' => $subscription->id,
            'gateway' => 'paypal',
            'gateway_invoice_id' => $resource['id'] ?? null,
            'number' => config('billing.invoice.prefix', 'INV').'-'.now()->format('Ymd').'-'.strtoupper(Str::random(6)),
            'total' => (float) ($resource['amount']['total'] ?? 0),
            'tax' => 0,
            'currency' => strtoupper($resource['amount']['currency'] ?? 'USD'),
            'status' => 'paid',
            'paid_at' => now(),
        ]);
    }
}
