<?php

declare(strict_types=1);

namespace App\Http\Controllers\Account;

use App\Events\SubscriptionCreated;
use App\Http\Controllers\Controller;
use App\Models\Coupon;
use App\Models\Plan;
use App\Services\Billing\BillingServiceFactory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

class CheckoutController extends Controller
{
    public function __construct(
        private BillingServiceFactory $billingFactory,
    ) {}

    public function show(Plan $plan): Response
    {
        if (! $plan->isAvailable()) {
            abort(404, 'This plan is not currently available.');
        }

        $user = request()->user();
        $stripeService = $this->billingFactory->make('stripe');

        // Fetch OS templates from VirtFusion if this is a VPS plan
        $osTemplates = [];
        $osTemplateGroups = [];
        if ($plan->service_type === 'vps') {
            try {
                $virtfusionService = app(\App\Services\Provisioning\VirtFusionService::class);
                $hypervisorId = $plan->features['virtfusion_package_id'] ?? 1;
                $templatesData = $virtfusionService->getTemplatesByPackage($hypervisorId);

                // Format flattened templates for backward compatibility
                $osTemplates = collect($templatesData['templates'])->map(fn ($t) => [
                    'id' => $t['id'],
                    'name' => ($t['name'] ?? 'Unknown').' '.($t['version'] ?? ''),
                    'description' => $t['description'] ?? '',
                    'category' => $this->categorizeOS($t['name'] ?? ''),
                    'icon' => $this->getOSIcon($t['name'] ?? ''),
                ])->toArray();

                // Format grouped templates for categorized display
                $osTemplateGroups = collect($templatesData['groups'])->map(function ($group) {
                    return [
                        'name' => $group['name'] ?? 'Other',
                        'description' => $group['description'] ?? '',
                        'icon' => $this->getOSIcon($group['name'] ?? ''),
                        'templates' => collect($group['templates'] ?? [])->map(fn ($t) => [
                            'id' => $t['id'],
                            'name' => ($t['name'] ?? 'Unknown').' '.($t['version'] ?? ''),
                            'description' => $t['description'] ?? '',
                            'category' => $this->categorizeOS($t['name'] ?? ''),
                            'icon' => $this->getOSIcon($t['name'] ?? ''),
                        ])->toArray(),
                    ];
                })->toArray();
            } catch (\Exception $e) {
                \Log::warning('Failed to fetch VirtFusion templates', ['error' => $e->getMessage()]);
            }
        }

        return Inertia::render('Checkout/Show', [
            'plan' => $plan,
            'paymentMethods' => $stripeService->getPaymentMethods($user),
            'intent' => $user->hasStripeId() ? $user->createSetupIntent() : null,
            'stripeKey' => config('cashier.key'),
            'osTemplates' => $osTemplates,
            'osTemplateGroups' => $osTemplateGroups,
        ]);
    }

    private function categorizeOS(string $name): string
    {
        $name = strtolower($name);

        if (str_contains($name, 'ubuntu')) {
            return 'ubuntu';
        }
        if (str_contains($name, 'debian')) {
            return 'debian';
        }
        if (str_contains($name, 'alma') || str_contains($name, 'rocky') || str_contains($name, 'centos') || str_contains($name, 'rhel')) {
            return 'redhat';
        }
        if (str_contains($name, 'fedora')) {
            return 'fedora';
        }
        if (str_contains($name, 'arch')) {
            return 'arch';
        }

        return 'linux';
    }

    private function getOSIcon(string $name): string
    {
        $category = $this->categorizeOS($name);

        return match ($category) {
            'ubuntu' => 'mdi-ubuntu',
            'debian' => 'mdi-debian',
            'redhat' => 'mdi-redhat',
            'fedora' => 'mdi-fedora',
            'arch' => 'mdi-arch',
            default => 'mdi-linux',
        };
    }

    public function store(Request $request, Plan $plan): RedirectResponse|JsonResponse
    {
        $request->validate([
            'gateway' => ['required', 'in:stripe,paypal'],
            'payment_method_id' => ['required_if:gateway,stripe', 'nullable', 'string'],
            'coupon_code' => ['nullable', 'string', 'max:50'],
            'billing_cycle' => ['required', 'in:monthly,quarterly,semi_annual,annual'],
            'configuration' => ['nullable', 'array'],
            'configuration.os_template_id' => ['nullable', 'integer'],
            'configuration.auth_method' => ['nullable', 'in:password,ssh'],
            'configuration.ssh_key' => ['nullable', 'string', 'max:4096'],
            'configuration.additional_ipv4' => ['nullable', 'integer', 'min:0', 'max:10'],
        ]);

        if (! $plan->isAvailable()) {
            return back()->with('error', 'This plan is not currently available.');
        }

        $user = $request->user();
        $gateway = $request->input('gateway');
        $couponCode = $request->input('coupon_code');
        $billingCycle = $request->input('billing_cycle', 'monthly');
        $service = $this->billingFactory->make($gateway);

        try {
            $result = $service->createSubscription(
                $user,
                $plan,
                $request->input('payment_method_id'),
                $couponCode,
                $billingCycle,
            );

            if ($couponCode) {
                $this->redeemCoupon($couponCode, $user, $plan);
            }

            // PayPal requires redirect to approval URL
            if ($gateway === 'paypal' && isset($result['approval_url'])) {
                return response()->json([
                    'redirect' => $result['approval_url'],
                ]);
            }

            // Stripe incomplete payment needs client-side confirmation
            if ($result['status'] === 'incomplete' && isset($result['client_secret'])) {
                return response()->json([
                    'requires_action' => true,
                    'client_secret' => $result['client_secret'],
                ]);
            }

            $subscription = $user->subscriptions()->latest()->first();
            if ($subscription) {
                // Store configuration on the subscription record for async provisioning
                if ($request->has('configuration')) {
                    $subscription->update(['provisioning_config' => json_encode($request->input('configuration'))]);
                }

                SubscriptionCreated::dispatch($user, $subscription);
            }

            return redirect()->route('account.dashboard')
                ->with('success', "Successfully subscribed to {$plan->name}!");
        } catch (\Exception $e) {
            return back()->with('error', 'Checkout failed: '.$e->getMessage());
        }
    }

    public function applyCoupon(Request $request): JsonResponse
    {
        $request->validate([
            'code' => ['required', 'string'],
            'plan_id' => ['required', 'exists:plans,id'],
        ]);

        $coupon = Coupon::where('code', $request->input('code'))->first();

        if (! $coupon || ! $coupon->isValid()) {
            return response()->json(['valid' => false, 'message' => 'Invalid or expired coupon.'], 422);
        }

        $plan = Plan::findOrFail($request->input('plan_id'));
        $discount = $this->calculateDiscount($coupon, $plan);

        return response()->json([
            'valid' => true,
            'discount' => $discount,
            'new_total' => max(0, $plan->price - $discount),
            'coupon_type' => $coupon->type,
            'coupon_value' => $coupon->value,
        ]);
    }

    public function paypalCallback(Request $request): RedirectResponse
    {
        $planId = $request->query('plan');
        $plan = Plan::findOrFail($planId);

        return redirect()->route('account.dashboard')
            ->with('success', "Successfully subscribed to {$plan->name}!");
    }

    public function paypalCancel(): RedirectResponse
    {
        return redirect()->route('account.plans.index')
            ->with('error', 'PayPal checkout was cancelled.');
    }

    private function redeemCoupon(string $code, \App\Models\User $user, Plan $plan): void
    {
        $coupon = Coupon::where('code', $code)->first();

        if ($coupon && $coupon->isValid()) {
            $discount = $this->calculateDiscount($coupon, $plan);

            $coupon->redemptions()->create([
                'user_id' => $user->id,
                'discount_amount' => $discount,
            ]);

            $coupon->increment('times_used');
        }
    }

    private function calculateDiscount(Coupon $coupon, Plan $plan): float
    {
        return match ($coupon->type) {
            'percentage' => round($plan->price * ($coupon->value / 100), 2),
            'fixed_amount' => min($coupon->value, $plan->price),
            default => 0,
        };
    }
}
