<?php

declare(strict_types=1);

namespace App\Http\Controllers\Academy;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Services\Academy\AcademyAccessService;
use App\Services\Academy\AcademyBillingPlanService;
use App\Support\AcademyAnalytics\AcademyAnalyticsContentType;
use App\Support\Seo\SeoFactory;
use Laravel\Cashier\Checkout;
use Laravel\Cashier\Subscription;

final class AcademyBillingController extends Controller
{
    public function __construct(
        private readonly AcademyAccessService $access,
        private readonly AcademyBillingPlanService $plans,
    ) {}

    public function pricing(\Illuminate\Http\Request $request): \Inertia\Response
    {
        \abort_unless((bool) \config('academy.enabled', true), 404);

        $this->plans->assertConfigured();

        /** @var User|null $user */
        $user = $request->user();
        $canonical = \route('academy.pricing');
        $seo = \app(SeoFactory::class)
            ->collectionPage(
                'Skinbase AI Academy Pricing — Skinbase',
                'Compare Skinbase AI Academy Creator and Pro tiers, start free, and manage premium access through Stripe billing.',
                $canonical,
            )
            ->toArray();

        $seo['og_type'] = 'website';
        $activePlan = $user instanceof User ? $this->activePlan($user) : null;

        return \Inertia\Inertia::render('Academy/Billing/Pricing', [
            'seo' => $seo,
            'billingEnabled' => $this->plans->enabled(),
            'currentTier' => $this->access->currentTier($user),
            'isSubscribed' => $user instanceof User ? $this->access->hasActiveAcademySubscription($user) : false,
            'activePlanKey' => $activePlan['key'] ?? null,
            'activePlanLabel' => $activePlan['label'] ?? null,
            'catalog' => $this->catalog(),
            'links' => [
                'login' => \route('login'),
                'pricing' => \route('academy.pricing'),
                'billingAccount' => $user ? \route('academy.billing.account') : null,
                'checkout' => $user ? \route('academy.billing.checkout') : null,
            ],
            'analytics' => [
                'enabled' => true,
                'contentType' => AcademyAnalyticsContentType::UPGRADE,
                'contentId' => null,
                'eventUrl' => \route('academy.analytics.events.store'),
                'pageName' => 'academy_billing_pricing',
                'isPremium' => false,
                'isGuest' => $user === null,
                'isSubscriber' => $user?->hasAcademyCreatorAccess() || $user?->hasAcademyProAccess(),
            ],
        ])->rootView('collections');
    }

    public function checkout(\Illuminate\Http\Request $request): Checkout|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
    {
        \abort_unless((bool) \config('academy.enabled', true), 404);

        if (! $this->plans->enabled()) {
            return $this->billingDisabledResponse($request, 'Academy billing is not enabled yet.');
        }

        $this->plans->assertConfigured();

        $user = $request->user();

        if (! $user instanceof User) {
            return \redirect()->route('login');
        }

        if ($user->email_verified_at === null) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'plan' => 'Verify your email address before starting Academy billing.',
            ]);
        }

        $validated = $request->validate([
            'plan' => ['required', 'string'],
        ]);

        $plan = $this->plans->plan((string) $validated['plan']);

        if ($plan === null) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'plan' => 'Select a valid Academy billing plan.',
            ]);
        }

        if (! ($plan['configured'] ?? false)) {
            return $this->missingPriceIdResponse($request, (string) $plan['key']);
        }

        if (! ($plan['price_id_valid'] ?? false)) {
            return $this->invalidPriceIdResponse($request, (string) $plan['key']);
        }

        if ($this->access->hasActiveAcademySubscription($user)) {
            return \redirect()->route('academy.billing.portal');
        }

        try {
            return $user
                ->newSubscription($this->plans->subscriptionName(), (string) $plan['stripe_price_id'])
                ->withMetadata([
                    'skinbase_module' => 'academy',
                    'user_id' => (string) $user->id,
                    'academy_plan' => (string) $plan['key'],
                    'academy_tier' => (string) $plan['tier'],
                ])
                ->checkout([
                    'success_url' => \route('academy.billing.success').'?session_id={CHECKOUT_SESSION_ID}',
                    'cancel_url' => \route('academy.billing.cancel'),
                    'allow_promotion_codes' => true,
                    'metadata' => [
                        'skinbase_module' => 'academy',
                        'user_id' => (string) $user->id,
                        'academy_plan' => (string) $plan['key'],
                        'academy_tier' => (string) $plan['tier'],
                    ],
                ]);
        } catch (\Throwable $exception) {
            \report($exception);

            return $this->checkoutErrorResponse($request, $exception);
        }
    }

    public function checkoutLegacy(\Illuminate\Http\Request $request, string $plan): Checkout|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
    {
        $request->merge([
            'plan' => $this->plans->normalizePlanKey($plan),
        ]);

        return $this->checkout($request);
    }

    public function portal(\Illuminate\Http\Request $request): \Illuminate\Http\RedirectResponse
    {
        \abort_unless((bool) \config('academy.enabled', true), 404);
        \abort_unless($this->plans->enabled(), 404);

        /** @var User|null $user */
        $user = $request->user();

        if (! $user instanceof User || \blank($user->stripe_id)) {
            return \redirect()->route('academy.billing.account')->with('error', 'No Stripe billing profile is connected to this account yet.');
        }

        return $user->redirectToBillingPortal(\route('academy.billing.account'));
    }

    public function success(\Illuminate\Http\Request $request): \Inertia\Response
    {
        \abort_unless((bool) \config('academy.enabled', true), 404);

        /** @var User|null $user */
        $user = $request->user();
        $currentTier = $this->access->currentTier($user);

        return \Inertia\Inertia::render('Academy/Billing/Success', [
            'message' => 'Payment is being confirmed. Your access will update automatically.',
            'currentTier' => $currentTier,
            'isSubscribed' => $user instanceof User ? $this->access->hasActiveAcademySubscription($user) : false,
            'links' => [
                'pricing' => \route('academy.pricing'),
                'account' => $user ? \route('academy.billing.account') : null,
                'academy' => \route('academy.index'),
            ],
            'sessionId' => $request->query('session_id'),
        ])->rootView('collections');
    }

    public function cancel(): \Inertia\Response
    {
        \abort_unless((bool) \config('academy.enabled', true), 404);

        return \Inertia\Inertia::render('Academy/Billing/Cancel', [
            'message' => 'Checkout was canceled. No payment was made.',
            'links' => [
                'pricing' => \route('academy.pricing'),
                'academy' => \route('academy.index'),
            ],
        ])->rootView('collections');
    }

    public function account(\Illuminate\Http\Request $request): \Inertia\Response
    {
        \abort_unless((bool) \config('academy.enabled', true), 404);
        \abort_unless($this->plans->enabled(), 404);

        /** @var User $user */
        $user = $request->user();
        $subscription = $this->academySubscription($user);

        $activePlan = $this->activePlan($user);

        return \Inertia\Inertia::render('Academy/Billing/Account', [
            'currentTier' => $this->access->currentTier($user),
            'isSubscribed' => $this->access->hasActiveAcademySubscription($user),
            'activePlan' => $activePlan ? [
                'key' => $activePlan['key'],
                'label' => $activePlan['label'],
                'price_display' => $activePlan['price_display'] ?? null,
                'tier' => $activePlan['tier'],
            ] : null,
            'subscription' => $subscription ? [
                'name' => $subscription->type,
                'status' => $subscription->stripe_status,
                'active' => $subscription->active(),
                'onGracePeriod' => $subscription->onGracePeriod(),
                'endsAt' => $subscription->ends_at?->toISOString(),
                'priceIds' => $subscription->items->pluck('stripe_price')->filter()->values()->all(),
            ] : null,
            'links' => [
                'portal' => \route('academy.billing.portal'),
                'pricing' => \route('academy.pricing'),
                'academy' => \route('academy.index'),
            ],
        ])->rootView('collections');
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private function catalog(): array
    {
        $definitions = [
            'creator' => [
                'name' => 'Creator',
                'description' => 'Entry premium access for prompt systems, creator lessons, and saved Academy workflows.',
                'badge' => 'Paid',
                'featured' => false,
                'features' => [
                    'Creator lessons and walkthroughs',
                    'Full Creator prompt templates',
                    'Prompt save and reuse flows',
                    'Upgrade path into Pro later',
                ],
            ],
            'pro' => [
                'name' => 'Pro',
                'description' => 'Full Academy access across Creator and Pro lessons, prompts, and future premium drops.',
                'badge' => 'Recommended',
                'featured' => true,
                'features' => [
                    'Everything in Creator',
                    'Advanced Pro lessons and prompt systems',
                    'Priority access to future Academy premium features',
                    'Stripe billing portal for upgrades and invoices',
                ],
            ],
        ];

        return collect($definitions)
            ->map(function (array $definition, string $tier): array {
                $plan = $this->plans->plan($tier.'_monthly');

                $plans = $plan !== null ? [[
                    'key' => $plan['key'],
                    'label' => $plan['label'],
                    'interval' => $plan['interval'],
                    'amount' => $plan['amount'],
                    'currency' => $plan['currency'],
                    'price_display' => $plan['price_display'],
                    'configured' => $plan['configured'],
                    'price_id_valid' => $plan['price_id_valid'],
                ]] : [];

                return [
                    'tier' => $tier,
                    'name' => $definition['name'],
                    'description' => $definition['description'],
                    'badge' => $definition['badge'],
                    'featured' => $definition['featured'],
                    'features' => $definition['features'],
                    'plans' => $plans,
                ];
            })
            ->values()
            ->all();
    }

    private function academySubscription(User $user): ?Subscription
    {
        $subscription = $user->subscription($this->plans->subscriptionName());

        return $subscription instanceof Subscription
            ? $subscription->loadMissing('items')
            : null;
    }

    /**
     * @return array<string, mixed>|null
     */
    private function activePlan(User $user): ?array
    {
        $subscription = $this->academySubscription($user);

        if (! $subscription instanceof Subscription || (! $subscription->active() && ! $subscription->onGracePeriod())) {
            return null;
        }

        $matchedPlan = null;

        foreach ($subscription->items as $item) {
            $priceId = trim((string) $item->stripe_price);

            if ($priceId === '') {
                continue;
            }

            $plan = $this->plans->planForPriceId($priceId);

            if ($plan === null) {
                continue;
            }

            if ($matchedPlan === null || $this->planRank((string) $plan['tier']) > $this->planRank((string) $matchedPlan['tier'])) {
                $matchedPlan = $plan;
            }
        }

        if ($matchedPlan !== null) {
            return $matchedPlan;
        }

        $fallbackPriceId = trim((string) $subscription->stripe_price);

        return $fallbackPriceId !== '' ? $this->plans->planForPriceId($fallbackPriceId) : null;
    }

    private function planRank(string $tier): int
    {
        return match (strtolower(trim($tier))) {
            'admin' => 40,
            'pro' => 30,
            'creator' => 20,
            default => 10,
        };
    }

    private function billingDisabledResponse(\Illuminate\Http\Request $request, string $message): \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
    {
        $payload = [
            'ok' => false,
            'code' => 'academy_payments_disabled',
            'message' => $message,
        ];

        if ($request->expectsJson()) {
            return \response()->json($payload, 423);
        }

        return \redirect()->route('academy.pricing')->with('error', $message);
    }

    private function missingPriceIdResponse(\Illuminate\Http\Request $request, string $planKey): \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
    {
        $message = 'The selected Academy plan is not configured yet. Please try again later.';

        if ($request->expectsJson()) {
            return \response()->json([
                'ok' => false,
                'code' => 'academy_billing_price_missing',
                'message' => $message,
                'plan' => $planKey,
            ], 422);
        }

        return \redirect()->route('academy.pricing')->with('error', $message);
    }

    private function invalidPriceIdResponse(\Illuminate\Http\Request $request, string $planKey): \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
    {
        $message = 'The selected Academy plan is misconfigured. Please contact support before continuing.';

        if ($request->expectsJson()) {
            return \response()->json([
                'ok' => false,
                'code' => 'academy_billing_price_invalid',
                'message' => $message,
                'plan' => $planKey,
            ], 422);
        }

        return \redirect()->route('academy.pricing')->with('error', $message);
    }

    private function checkoutErrorResponse(\Illuminate\Http\Request $request, \Throwable $exception): \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
    {
        $message = 'Academy checkout could not be started right now.';

        if (app()->hasDebugModeEnabled() && trim($exception->getMessage()) !== '') {
            $message .= ' '.$exception->getMessage();
        }

        if ($request->expectsJson()) {
            return \response()->json([
                'ok' => false,
                'code' => 'academy_billing_checkout_failed',
                'message' => $message,
            ], 422);
        }

        return \redirect()->route('academy.pricing')->with('error', $message);
    }
}