<?php

declare(strict_types=1);

namespace App\Http\Controllers\Account;

use App\Events\SubscriptionCancelled;
use App\Http\Controllers\Controller;
use App\Models\CancellationSurvey;
use App\Models\Plan;
use App\Services\Billing\BillingServiceFactory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

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

    public function index(Request $request): Response
    {
        $subscriptions = $request->user()
            ->subscriptions()
            ->select([
                'subscriptions.*',
                'plans.name as plan_name',
                'plans.price as plan_price',
                'plans.billing_cycle as plan_billing_cycle',
                'plans.service_type as plan_service_type',
            ])
            ->leftJoin('plans', 'subscriptions.plan_id', '=', 'plans.id')
            ->latest('subscriptions.created_at')
            ->get();

        return Inertia::render('Subscriptions/Index', [
            'subscriptions' => $subscriptions,
        ]);
    }

    public function show(Request $request, int $subscriptionId): Response
    {
        $subscription = $request->user()
            ->subscriptions()
            ->select([
                'subscriptions.*',
                'plans.name as plan_name',
                'plans.price as plan_price',
                'plans.billing_cycle as plan_billing_cycle',
                'plans.service_type as plan_service_type',
                'plans.features as plan_features',
            ])
            ->leftJoin('plans', 'subscriptions.plan_id', '=', 'plans.id')
            ->where('subscriptions.id', $subscriptionId)
            ->firstOrFail();

        // Decode plan_features since leftJoin bypasses Eloquent casts
        if (is_string($subscription->plan_features)) {
            $subscription->plan_features = json_decode($subscription->plan_features, true);
        }

        $availablePlans = Plan::query()
            ->where('status', 'active')
            ->where('service_type', $subscription->plan_service_type)
            ->where('id', '!=', $subscription->plan_id)
            ->orderBy('price')
            ->get();

        return Inertia::render('Subscriptions/Show', [
            'subscription' => $subscription,
            'availablePlans' => $availablePlans,
        ]);
    }

    public function cancel(Request $request, int $subscriptionId): RedirectResponse
    {
        $subscription = $request->user()
            ->subscriptions()
            ->findOrFail($subscriptionId);

        $gateway = $subscription->gateway ?? 'stripe';
        $service = $this->billingFactory->make($gateway);

        $gatewayId = $gateway === 'stripe'
            ? $subscription->stripe_id
            : $subscription->gateway_subscription_id;

        $success = $service->cancelSubscription(
            $request->user(),
            $gatewayId,
            $request->boolean('immediately'),
        );

        if (! $success) {
            return back()->with('error', 'Failed to cancel subscription. Please try again.');
        }

        $reason = $request->input('reason', '');

        CancellationSurvey::create([
            'user_id' => $request->user()->id,
            'subscription_id' => $subscription->id,
            'cancellation_reason' => $reason,
            'cancellation_feedback' => $request->input('feedback'),
            'would_return' => $request->input('would_return'),
        ]);

        SubscriptionCancelled::dispatch($request->user(), $subscription, $reason ?: null);

        return back()->with('success', 'Subscription has been cancelled.');
    }

    public function resume(Request $request, int $subscriptionId): RedirectResponse
    {
        $subscription = $request->user()
            ->subscriptions()
            ->findOrFail($subscriptionId);

        $gateway = $subscription->gateway ?? 'stripe';
        $service = $this->billingFactory->make($gateway);

        $gatewayId = $gateway === 'stripe'
            ? $subscription->stripe_id
            : $subscription->gateway_subscription_id;

        $success = $service->resumeSubscription($request->user(), $gatewayId);

        if (! $success) {
            return back()->with('error', 'Failed to resume subscription. Please try again.');
        }

        return back()->with('success', 'Subscription has been resumed.');
    }

    public function swap(Request $request, int $subscriptionId): RedirectResponse
    {
        $request->validate([
            'plan_id' => ['required', 'exists:plans,id'],
        ]);

        $subscription = $request->user()
            ->subscriptions()
            ->findOrFail($subscriptionId);

        $newPlan = Plan::findOrFail($request->input('plan_id'));
        $gateway = $subscription->gateway ?? 'stripe';
        $service = $this->billingFactory->make($gateway);

        $gatewayId = $gateway === 'stripe'
            ? $subscription->stripe_id
            : $subscription->gateway_subscription_id;

        try {
            $service->swapSubscription($request->user(), $gatewayId, $newPlan);

            return back()->with('success', "Plan changed to {$newPlan->name}.");
        } catch (\Exception $e) {
            return back()->with('error', 'Failed to change plan: '.$e->getMessage());
        }
    }
}
