<?php

namespace App\Http\Controllers\Api\Billing;

use App\Domains\Billing\Actions\CreateTenantBillingInvoiceAction;
use App\Domains\Billing\Models\Plan;
use App\Domains\Billing\Models\Subscription;
use App\Domains\Billing\Models\TenantBillingInvoice;
use App\Http\Controllers\Controller;
use App\Support\PlatformSettings;
use Illuminate\Http\JsonResponse;
use RuntimeException;

class TenantBillingPortalController extends Controller
{
    public function __invoke(CreateTenantBillingInvoiceAction $createTenantBillingInvoice): JsonResponse
    {
        $user = request()->user();
        $tenant = $user->tenant()->with('plan')->firstOrFail();
        $subscription = Subscription::query()
            ->with('plan')
            ->where('tenant_id', $tenant->getKey())
            ->latest('created_at')
            ->first();

        if (
            $subscription
            && $subscription->ends_at
            && now()->greaterThanOrEqualTo($subscription->ends_at)
            && in_array($subscription->status, ['active', 'paid', 'succeeded', 'past_due'], true)
            && $tenant->plan
        ) {
            $hasOpenRenewalInvoice = TenantBillingInvoice::query()
                ->where('tenant_id', $tenant->getKey())
                ->where('plan_id', $tenant->plan_id)
                ->whereIn('status', ['draft', 'initiated', 'pending_payment'])
                ->exists();

            if (! $hasOpenRenewalInvoice) {
                try {
                    $createTenantBillingInvoice->execute(
                        tenant: $tenant,
                        plan: $tenant->plan,
                        user: $user,
                        billingCycle: $this->resolveBillingCycle($subscription),
                    );
                } catch (RuntimeException) {
                    // Keep portal usable even if renewal invoice generation fails.
                }
            }
        }
        $subscriptionEndsAt = $subscription?->ends_at;
        $isExpired = (bool) ($subscriptionEndsAt && now()->greaterThanOrEqualTo($subscriptionEndsAt));
        $expiresInDays = $subscriptionEndsAt ? now()->diffInDays($subscriptionEndsAt, false) : null;
        $plans = Plan::query()
            ->where('is_active', true)
            ->orderBy('monthly_price')
            ->get()
            ->map(fn (Plan $plan) => [
                'id' => $plan->id,
                'name' => $plan->name,
                'slug' => $plan->slug,
                'monthlyPrice' => '$'.number_format((float) $plan->monthly_price, 2),
                'yearlyPrice' => $plan->yearly_price !== null ? '$'.number_format((float) $plan->yearly_price, 2) : null,
                'maxUsers' => $plan->max_users,
                'maxBranches' => $plan->max_branches,
                'maxChannels' => $plan->max_channels,
                'maxAutomations' => $plan->max_automations,
                'features' => collect($plan->features_json ?? [])
                    ->filter()
                    ->keys()
                    ->values()
                    ->all(),
                'isCurrent' => $tenant->plan_id === $plan->id,
            ])
            ->values();

        $invoices = TenantBillingInvoice::query()
            ->with(['plan', 'provider'])
            ->where('tenant_id', $tenant->getKey())
            ->latest('created_at')
            ->limit(12)
            ->get()
            ->map(fn (TenantBillingInvoice $invoice) => [
                'id' => $invoice->id,
                'invoiceNumber' => $invoice->invoice_number,
                'planName' => $invoice->plan?->name ?? 'Unknown',
                'billingCycle' => $invoice->billing_cycle,
                'status' => $invoice->status,
                'amount' => '$'.number_format((float) $invoice->amount, 2),
                'currencyCode' => $invoice->currency_code,
                'checkoutUrl' => $invoice->checkout_url,
                'paidAt' => $invoice->paid_at?->format('M d, Y H:i'),
                'dueAt' => $invoice->due_at?->format('M d, Y'),
                'provider' => $invoice->provider?->display_name,
            ])
            ->values();

        $providerConfigured = $tenant->paymentProviders()
            ->where('provider_key', (string) PlatformSettings::get('PAYMENT_DEFAULT_PROVIDER', config('payments.default_provider', 'whish')))
            ->where('is_enabled', true)
            ->exists();

        return response()->json([
            'data' => [
                'tenant' => [
                    'companyName' => $tenant->company_name,
                    'status' => $tenant->status,
                    'currencyCode' => $tenant->currency_code,
                    'trialEndsAt' => $tenant->trial_ends_at?->format('M d, Y'),
                ],
                'currentPlan' => $tenant->plan ? [
                    'id' => $tenant->plan->id,
                    'name' => $tenant->plan->name,
                    'slug' => $tenant->plan->slug,
                    'monthlyPrice' => '$'.number_format((float) $tenant->plan->monthly_price, 2),
                    'maxUsers' => $tenant->plan->max_users,
                    'maxBranches' => $tenant->plan->max_branches,
                    'maxChannels' => $tenant->plan->max_channels,
                    'maxAutomations' => $tenant->plan->max_automations,
                ] : null,
                'subscription' => $subscription ? [
                    'status' => $subscription->status,
                    'startsAt' => $subscription->starts_at?->format('M d, Y'),
                    'endsAt' => $subscription->ends_at?->format('M d, Y'),
                    'endsAtIso' => $subscription->ends_at?->toIso8601String(),
                    'trialEndsAt' => $subscription->trial_ends_at?->format('M d, Y'),
                    'isExpired' => $isExpired,
                    'expiresInDays' => $expiresInDays,
                ] : null,
                'plans' => $plans,
                'invoices' => $invoices,
                'providerConfigured' => $providerConfigured,
            ],
        ]);
    }

    private function resolveBillingCycle(Subscription $subscription): string
    {
        if (! $subscription->starts_at || ! $subscription->ends_at) {
            return 'monthly';
        }

        return $subscription->starts_at->diffInDays($subscription->ends_at) > 60 ? 'yearly' : 'monthly';
    }
}
