<?php

namespace App\Http\Controllers\Billing;

use App\Http\Controllers\Controller;
use App\Models\Order;
use App\Models\Payment;
use App\Models\PricingPlan;
use App\Models\Subscription;
use App\Models\User;
use App\Models\WebhookEvent;
use App\Services\System\SettingsService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;

class PayPalController extends Controller
{
    public function createSubscription(Request $request): RedirectResponse|JsonResponse
    {
        $data = $request->validate([
            'plan_code' => 'required|string|in:personal_monthly,personal_annual',
        ]);

        $user = $request->user();
        if (!$user) {
            return response()->json(['error' => 'auth_required'], 401);
        }

        $mode = $this->billingMode();
        if (!$this->paypalConfigured($mode)) {
            return response()->json(['error' => 'paypal_not_configured'], 422);
        }
        $planId = $this->resolvePlanId($data['plan_code'], $mode);
        if (!$planId) {
            return response()->json(['error' => 'paypal_plan_missing'], 422);
        }

        $token = $this->getAccessToken($mode);
        if (!$token) {
            return response()->json(['error' => 'paypal_auth_failed'], 502);
        }

        $appUrl = rtrim(config('app.url'), '/');
        $payload = [
            'plan_id' => $planId,
            'subscriber' => [
                'name' => [
                    'given_name' => $user->name ?? 'User',
                    'surname' => 'Dewemoji',
                ],
                'email_address' => $user->email,
            ],
            'application_context' => [
                'brand_name' => 'Dewemoji',
                'locale' => 'en-US',
                'user_action' => 'SUBSCRIBE_NOW',
                'return_url' => $appUrl.'/billing/paypal/return?status=success',
                'cancel_url' => $appUrl.'/billing/paypal/return?status=cancel',
            ],
        ];

        $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base");
        $res = Http::withToken($token)
            ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10))
            ->post(rtrim($apiBase, '/').'/v1/billing/subscriptions', $payload);

        $body = $res->json();
        $subscriptionId = $body['id'] ?? null;
        $approveUrl = collect($body['links'] ?? [])->firstWhere('rel', 'approve')['href'] ?? null;

        if (!$subscriptionId || !$approveUrl) {
            if (!$res->ok()) {
                Log::warning('PayPal create subscription failed', [
                    'status' => $res->status(),
                    'body' => $res->body(),
                ]);
            } else {
                Log::warning('PayPal create subscription missing approve link', [
                    'status' => $res->status(),
                    'body' => $res->body(),
                ]);
            }
            return response()->json(['error' => 'paypal_invalid_response'], 502);
        }

        $amountUsd = $this->resolvePlanAmountUsd($data['plan_code']);

        Subscription::where('user_id', $user->id)
            ->where('provider', 'paypal')
            ->where('status', 'pending')
            ->update(['status' => 'cancelled']);
        Order::where('user_id', $user->id)
            ->where('provider', 'paypal')
            ->where('status', 'pending')
            ->update(['status' => 'cancelled']);
        Payment::where('user_id', $user->id)
            ->where('provider', 'paypal')
            ->where('status', 'pending')
            ->update(['status' => 'cancelled']);

        $order = Order::create([
            'user_id' => $user->id,
            'plan_code' => $data['plan_code'],
            'type' => 'subscription',
            'currency' => 'USD',
            'amount' => $amountUsd,
            'status' => 'pending',
            'provider' => 'paypal',
            'provider_ref' => $subscriptionId,
        ]);

        Payment::create([
            'user_id' => $user->id,
            'order_id' => $order->id,
            'provider' => 'paypal',
            'type' => 'subscription',
            'plan_code' => $data['plan_code'],
            'currency' => 'USD',
            'amount' => $amountUsd,
            'status' => 'pending',
            'provider_ref' => $subscriptionId,
            'raw_payload' => $body,
        ]);

        Subscription::firstOrCreate([
            'provider' => 'paypal',
            'provider_ref' => $subscriptionId,
        ], [
            'user_id' => $user->id,
            'plan' => $data['plan_code'],
            'status' => 'pending',
            'started_at' => now(),
        ]);

        return response()->json(['approve_url' => $approveUrl]);
    }

    public function return(Request $request): RedirectResponse
    {
        $status = (string) $request->query('status', 'success');
        return redirect()->route('dashboard.billing', ['status' => $status]);
    }

    public function webhook(Request $request): JsonResponse
    {
        $payload = $request->all();
        $eventId = (string) ($payload['id'] ?? '');
        $eventType = (string) ($payload['event_type'] ?? '');

        $mode = config('dewemoji.billing.mode', 'sandbox');
        $webhookId = config("dewemoji.billing.providers.paypal.webhook_ids.{$mode}");

        if ($webhookId) {
            $verified = $this->verifySignature($mode, $webhookId, $payload, $request);
            if (!$verified) {
                return response()->json(['error' => 'invalid_signature'], 401);
            }
        }

        $event = WebhookEvent::create([
            'provider' => 'paypal',
            'event_id' => $eventId ?: (string) Str::uuid(),
            'event_type' => $eventType,
            'status' => 'received',
            'payload' => $payload,
            'headers' => $request->headers->all(),
            'received_at' => now(),
        ]);

        try {
            $processed = $this->processPayPalEvent($payload);
            $event->update([
                'status' => $processed ? 'processed' : 'received',
                'processed_at' => $processed ? now() : null,
            ]);
        } catch (\Throwable $e) {
            $event->update([
                'status' => 'error',
                'error' => $e->getMessage(),
                'processed_at' => now(),
            ]);
        }

        return response()->json(['ok' => true]);
    }

    private function processPayPalEvent(array $payload): bool
    {
        $type = (string) ($payload['event_type'] ?? '');
        $resource = $payload['resource'] ?? [];
        $subscriptionId = (string) ($resource['id'] ?? $resource['subscription_id'] ?? '');

        if ($subscriptionId === '') {
            return false;
        }

        if ($type === 'BILLING.SUBSCRIPTION.ACTIVATED') {
            $sub = Subscription::firstOrNew([
                'provider' => 'paypal',
                'provider_ref' => $subscriptionId,
            ]);
            if (!$sub->user_id) {
                $order = Order::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->first();
                if ($order) {
                    $sub->user_id = $order->user_id;
                }
            }
            $sub->status = 'active';
            $sub->started_at = $sub->started_at ?? now();
            $sub->next_renewal_at = $resource['billing_info']['next_billing_time'] ?? null;
            $sub->save();

            if ($sub->user_id) {
                User::where('id', $sub->user_id)->update(['tier' => 'personal']);
            }

            Order::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->update(['status' => 'paid']);
            Payment::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->update(['status' => 'paid']);

            return true;
        }

        if (in_array($type, ['BILLING.SUBSCRIPTION.CANCELLED', 'BILLING.SUBSCRIPTION.SUSPENDED'], true)) {
            $sub = Subscription::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->first();
            if ($sub) {
                $sub->status = 'canceled';
                $sub->canceled_at = now();
                $sub->save();
            }
            return true;
        }

        return false;
    }

    private function resolvePlanId(string $planCode, string $mode): ?string
    {
        $plan = PricingPlan::where('code', $planCode)->first();
        if ($plan) {
            $meta = $plan->meta ?? [];
            $stored = $meta['paypal'][$mode]['plan']['id'] ?? null;
            if ($stored) {
                return $stored;
            }
        }

        return config("dewemoji.billing.providers.paypal.plan_ids.{$mode}.{$planCode}") ?: null;
    }

    private function resolvePlanAmountUsd(string $planCode): int
    {
        $plan = PricingPlan::where('code', $planCode)->first();
        if (!$plan) {
            return 0;
        }
        $rate = (int) config('dewemoji.pricing.usd_rate', 15000);
        if ($rate <= 0) {
            return 0;
        }
        return (int) round($plan->amount / $rate);
    }

    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($apiBase, '/').'/v1/oauth2/token', [
                'grant_type' => 'client_credentials',
            ]);

        if (!$res->ok()) {
            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 billingMode(): string
    {
        $settings = app(SettingsService::class);
        return (string) ($settings->get('billing_mode', config('dewemoji.billing.mode', 'sandbox')) ?: 'sandbox');
    }

    private function verifySignature(string $mode, string $webhookId, array $payload, Request $request): bool
    {
        $token = $this->getAccessToken($mode);
        if (!$token) {
            return false;
        }

        $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base");
        $verifyPayload = [
            'auth_algo' => $request->header('paypal-auth-algo'),
            'cert_url' => $request->header('paypal-cert-url'),
            'transmission_id' => $request->header('paypal-transmission-id'),
            'transmission_sig' => $request->header('paypal-transmission-sig'),
            'transmission_time' => $request->header('paypal-transmission-time'),
            'webhook_id' => $webhookId,
            'webhook_event' => $payload,
        ];

        if (collect($verifyPayload)->contains(fn ($v) => empty($v))) {
            return false;
        }

        $res = Http::withToken($token)
            ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10))
            ->post(rtrim($apiBase, '/').'/v1/notifications/verify-webhook-signature', $verifyPayload);

        return $res->ok() && $res->json('verification_status') === 'SUCCESS';
    }
}
