<?php

namespace App\Services;

use App\Models\Plan;
use App\Models\SaasSubscription;
use App\Models\UsageCounter;
use App\Models\User;
use Carbon\CarbonImmutable;

class EntitlementService
{
    public function activeSubscription(User $user): ?SaasSubscription
    {
        if ($user->isSuperAdmin()) {
            return null;
        }

        return SaasSubscription::query()
            ->with('plan.features')
            ->where('user_id', $user->id)
            ->whereIn('status', ['active', 'trialing'])
            ->orderByDesc('id')
            ->first();
    }

    public function activePlan(User $user): ?Plan
    {
        if ($user->isSuperAdmin()) {
            return Plan::query()->where('slug', 'enterprise')->first();
        }

        return $this->activeSubscription($user)?->plan;
    }

    public function can(User $user, string $featureKey): bool
    {
        if ($user->isSuperAdmin()) {
            return true;
        }

        $subscription = $this->activeSubscription($user);
        if ($subscription === null || $subscription->plan === null || ! $subscription->plan->is_active) {
            return false;
        }

        return $subscription->plan->features->contains(fn ($feature) => $feature->feature_key === $featureKey);
    }

    public function enforce(User $user, string $featureKey): void
    {
        abort_unless($this->can($user, $featureKey), 403);
    }

    public function remaining(User $user, string $metricKey): ?int
    {
        if ($user->isSuperAdmin()) {
            return null;
        }

        $subscription = $this->activeSubscription($user);
        if ($subscription === null || $subscription->plan === null) {
            return 0;
        }

        $planFeature = $subscription->plan->features->firstWhere('feature_key', $metricKey);
        if ($planFeature === null) {
            return 0;
        }

        if ($planFeature->limit === null) {
            return null;
        }

        $period = CarbonImmutable::now()->format('Y-m');
        $used = UsageCounter::query()
            ->where('user_id', $user->id)
            ->where('metric_key', $metricKey)
            ->where('period', $period)
            ->value('count') ?? 0;

        return max(0, $planFeature->limit - $used);
    }

    public function consume(User $user, string $metricKey, int $amount = 1): void
    {
        if ($user->isSuperAdmin()) {
            return;
        }

        $remaining = $this->remaining($user, $metricKey);
        abort_if($remaining !== null && $remaining < $amount, 403);

        $period = CarbonImmutable::now()->format('Y-m');
        $counter = UsageCounter::query()->firstOrCreate(
            ['user_id' => $user->id, 'metric_key' => $metricKey, 'period' => $period],
            ['count' => 0]
        );
        $counter->increment('count', $amount);
    }
}
