<?php

declare(strict_types=1);

namespace App\Http\Controllers\Account;

use App\Http\Controllers\Controller;
use App\Models\AuditLog;
use App\Models\Invoice;
use App\Models\Plan;
use App\Models\Service;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

class UpgradeController extends Controller
{
    public function show(Request $request, Service $service): Response
    {
        abort_unless($service->user_id === $request->user()->id, 403);
        abort_unless($service->isActive(), 403, 'Only active services can be upgraded or downgraded.');

        $service->load('plan');

        $currentPlan = $service->plan;

        $availablePlans = Plan::query()
            ->where('service_type', $currentPlan->service_type)
            ->where('status', 'active')
            ->where('id', '!=', $currentPlan->id)
            ->where(function ($query) {
                $query->whereNull('stock_quantity')
                    ->orWhere('stock_quantity', '>', 0);
            })
            ->orderBy('price')
            ->get()
            ->map(function (Plan $plan) use ($currentPlan): array {
                $currentPrice = (float) $currentPlan->price;
                $newPrice = (float) $plan->price;
                $priceDifference = round($newPrice - $currentPrice, 2);

                return [
                    ...$plan->toArray(),
                    'price_difference' => $priceDifference,
                    'is_upgrade' => $priceDifference > 0,
                ];
            });

        return Inertia::render('Services/Upgrade', [
            'service' => $service,
            'currentPlan' => $currentPlan,
            'availablePlans' => $availablePlans,
        ]);
    }

    public function store(Request $request, Service $service): RedirectResponse
    {
        abort_unless($service->user_id === $request->user()->id, 403);
        abort_unless($service->isActive(), 403, 'Only active services can be upgraded or downgraded.');

        $validated = $request->validate([
            'plan_id' => ['required', 'integer', 'exists:plans,id'],
        ]);

        $service->load('plan');
        $currentPlan = $service->plan;
        $newPlan = Plan::findOrFail($validated['plan_id']);

        abort_unless($newPlan->service_type === $currentPlan->service_type, 422, 'Cannot switch to a plan of a different service type.');
        abort_unless($newPlan->isAvailable(), 422, 'The selected plan is not available.');
        abort_if($newPlan->id === $currentPlan->id, 422, 'You are already on this plan.');

        $currentPrice = (float) $currentPlan->price;
        $newPrice = (float) $newPlan->price;
        $priceDifference = round($newPrice - $currentPrice, 2);
        $isUpgrade = $priceDifference > 0;

        DB::transaction(function () use ($service, $currentPlan, $newPlan, $priceDifference, $isUpgrade, $request): void {
            $oldPlanId = $service->plan_id;

            $service->update([
                'plan_id' => $newPlan->id,
            ]);

            if ($priceDifference !== 0.0) {
                $invoiceNumber = 'INV-'.strtoupper(uniqid());
                $invoiceStatus = $isUpgrade ? 'pending' : 'paid';
                $invoiceTotal = abs($priceDifference);

                $description = $isUpgrade
                    ? "Upgrade from {$currentPlan->name} to {$newPlan->name}"
                    : "Credit: Downgrade from {$currentPlan->name} to {$newPlan->name}";

                $invoice = Invoice::create([
                    'user_id' => $request->user()->id,
                    'subscription_id' => $service->subscription_id,
                    'gateway' => 'internal',
                    'number' => $invoiceNumber,
                    'total' => $isUpgrade ? $invoiceTotal : -$invoiceTotal,
                    'tax' => 0,
                    'currency' => 'USD',
                    'status' => $invoiceStatus,
                    'due_date' => $isUpgrade ? now()->addDays(7) : null,
                    'paid_at' => $isUpgrade ? null : now(),
                ]);

                $invoice->items()->create([
                    'description' => $description,
                    'amount' => $isUpgrade ? $invoiceTotal : -$invoiceTotal,
                    'quantity' => 1,
                ]);
            }

            AuditLog::create([
                'user_id' => $request->user()->id,
                'action' => $isUpgrade ? 'service.upgrade' : 'service.downgrade',
                'resource_type' => 'service',
                'resource_id' => $service->id,
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'changes' => [
                    'old_plan_id' => $oldPlanId,
                    'new_plan_id' => $newPlan->id,
                    'old_plan_name' => $currentPlan->name,
                    'new_plan_name' => $newPlan->name,
                    'price_difference' => $priceDifference,
                ],
            ]);
        });

        $actionLabel = $isUpgrade ? 'upgraded' : 'downgraded';

        return redirect()->route('account.services.show', $service)
            ->with('success', "Service successfully {$actionLabel} to {$newPlan->name}.");
    }
}
