<?php

declare(strict_types=1);

namespace App\Http\Controllers\Account;

use App\Http\Controllers\Controller;
use App\Models\Invoice;
use App\Services\Billing\BillingServiceFactory;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

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

    public function index(Request $request): Response
    {
        $user = $request->user();
        $stripeService = $this->billingFactory->make('stripe');

        return Inertia::render('Billing/Index', [
            'paymentMethods' => $stripeService->getPaymentMethods($user),
            'invoices' => $user->billingInvoices()
                ->latest()
                ->take(20)
                ->get(),
            'transactions' => $user->paymentTransactions()
                ->latest()
                ->take(20)
                ->get(),
            'intent' => $user->hasStripeId() ? $user->createSetupIntent() : null,
            'stripeKey' => config('cashier.key'),
        ]);
    }

    public function addPaymentMethod(Request $request): RedirectResponse
    {
        $request->validate([
            'payment_method_id' => ['required', 'string'],
        ]);

        $service = $this->billingFactory->make('stripe');
        $success = $service->addPaymentMethod($request->user(), $request->input('payment_method_id'));

        if (! $success) {
            return back()->with('error', 'Failed to add payment method.');
        }

        return back()->with('success', 'Payment method added.');
    }

    public function removePaymentMethod(Request $request, string $paymentMethodId): RedirectResponse
    {
        $service = $this->billingFactory->make('stripe');
        $service->removePaymentMethod($request->user(), $paymentMethodId);

        return back()->with('success', 'Payment method removed.');
    }

    public function setDefaultPaymentMethod(Request $request): RedirectResponse
    {
        $request->validate([
            'payment_method_id' => ['required', 'string'],
        ]);

        $service = $this->billingFactory->make('stripe');
        $service->setDefaultPaymentMethod($request->user(), $request->input('payment_method_id'));

        return back()->with('success', 'Default payment method updated.');
    }

    public function paymentMethods(Request $request): Response
    {
        $user = $request->user();
        $paymentMethods = [];
        $defaultPaymentMethod = null;

        if ($user->hasStripeId()) {
            $methods = $user->paymentMethods();
            $defaultPm = $user->defaultPaymentMethod();
            $defaultPaymentMethod = $defaultPm?->id;

            foreach ($methods as $method) {
                $paymentMethods[] = [
                    'id' => $method->id,
                    'brand' => $method->card->brand ?? 'unknown',
                    'last_four' => $method->card->last4 ?? '****',
                    'exp_month' => $method->card->exp_month,
                    'exp_year' => $method->card->exp_year,
                    'is_default' => $method->id === $defaultPaymentMethod,
                ];
            }
        }

        // Create setup intent for adding new cards
        if (! $user->hasStripeId()) {
            $user->createAsStripeCustomer();
        }

        return Inertia::render('Billing/PaymentMethods', [
            'paymentMethods' => $paymentMethods,
            'defaultPaymentMethod' => $defaultPaymentMethod,
            'intent' => $user->createSetupIntent(),
            'stripeKey' => config('cashier.key'),
        ]);
    }

    public function invoices(Request $request): Response
    {
        $invoices = $request->user()
            ->billingInvoices()
            ->latest()
            ->paginate(20);

        return Inertia::render('Billing/Invoices', [
            'invoices' => $invoices,
        ]);
    }

    public function downloadInvoice(Request $request, Invoice $invoice): \Symfony\Component\HttpFoundation\Response
    {
        if ($invoice->user_id !== $request->user()->id) {
            abort(403);
        }

        $invoice->load(['user', 'items']);

        $pdf = Pdf::loadView('pdf.invoice', ['invoice' => $invoice]);

        return $pdf->download("invoice-{$invoice->number}.pdf");
    }

    public function transactions(Request $request): Response
    {
        $transactions = $request->user()
            ->paymentTransactions()
            ->latest()
            ->paginate(20);

        return Inertia::render('Billing/Transactions', [
            'transactions' => $transactions,
        ]);
    }

    public function credits(Request $request): Response
    {
        $user = $request->user();

        $credits = $user->accountCredits()
            ->latest()
            ->paginate(20);

        return Inertia::render('Billing/Credits', [
            'credits' => $credits,
            'creditBalance' => (float) $user->credit_balance,
        ]);
    }

    public function upcomingRenewals(Request $request): Response
    {
        $user = $request->user();

        $renewals = $user->subscriptions()
            ->select([
                'subscriptions.*',
                'plans.name as plan_name',
                'plans.price as plan_price',
                'plans.billing_cycle as plan_billing_cycle',
            ])
            ->leftJoin('plans', 'subscriptions.plan_id', '=', 'plans.id')
            ->whereIn('stripe_status', ['active', 'trialing'])
            ->whereNotNull('current_period_end')
            ->orderBy('current_period_end')
            ->get()
            ->map(function ($subscription) use ($user) {
                $service = $user->services()
                    ->where('subscription_id', $subscription->id)
                    ->first();

                return [
                    'id' => $subscription->id,
                    'plan_name' => $subscription->plan_name ?? $subscription->type,
                    'plan_price' => $subscription->plan_price,
                    'billing_cycle' => $subscription->plan_billing_cycle,
                    'renewal_date' => $subscription->current_period_end,
                    'status' => $subscription->stripe_status,
                    'auto_renew' => $service?->auto_renew ?? true,
                    'service_id' => $service?->id,
                    'days_until_renewal' => now()->diffInDays($subscription->current_period_end, false),
                ];
            });

        return Inertia::render('Billing/UpcomingRenewals', [
            'renewals' => $renewals,
        ]);
    }

    public function setupIntent(Request $request): JsonResponse
    {
        $user = $request->user();

        if (! $user->hasStripeId()) {
            $user->createAsStripeCustomer();
        }

        return response()->json([
            'client_secret' => $user->createSetupIntent()->client_secret,
        ]);
    }
}
