<?php

namespace App\Modules\Admin\Tenancy\Services;

use App\Exceptions\PlanLimitExceededException;
use App\Modules\Admin\Tenancy\Models\Tenant;
use App\Modules\Admin\Tenancy\Repositories\PlanLimitRepository;
use App\Modules\Admin\Tenancy\Repositories\PlanLimitUsageRepository;
use App\Modules\Admin\Tenancy\Support\PlanLimitKeys;

class PlanLimitEnforcementService
{
    public function __construct(
        private readonly PlanLimitRepository $limits,
        private readonly PlanLimitUsageRepository $usage,
        private readonly PlanLimitNotifier $notifier,
    ) {}

    public function effectiveCap(Tenant $tenant, string $limitKey): ?int
    {
        $planId = $this->resolvePlanId($tenant);
        if ($planId === null) {
            return null;
        }

        $row = $this->limits->findForPlan($planId, $limitKey);
        $cap = $this->capFromRow($row);
        if ($cap !== null || $limitKey !== PlanLimitKeys::CUSTOM_FIELDS_LIMIT) {
            return $cap;
        }

        $legacy = $this->limits->findForPlan($planId, PlanLimitKeys::CUSTOM_FIELDS_FEATURE);

        return $this->capFromRow($legacy);
    }

    public function currentUsage(Tenant $tenant, string $limitKey): int
    {
        return match ($limitKey) {
            PlanLimitKeys::EMPLOYEES_LIMIT => $this->usage->countEmployeesForTenant((int) $tenant->id),
            PlanLimitKeys::CUSTOM_FIELDS_LIMIT => $this->usage->countActiveCustomFieldsForTenant((int) $tenant->id),
            default => 0,
        };
    }

    public function assertCanIncrement(Tenant $tenant, string $limitKey): void
    {
        $cap = $this->effectiveCap($tenant, $limitKey);
        if ($cap === null) {
            return;
        }
        $used = $this->currentUsage($tenant, $limitKey);
        if ($used >= $cap) {
            $this->notifier->notifyBlockedIfNeeded($tenant, $limitKey, $used, $cap);
            throw new PlanLimitExceededException($limitKey, $cap, $used);
        }
    }

    public function evaluateAfterIncrement(Tenant $tenant, string $limitKey): void
    {
        $cap = $this->effectiveCap($tenant, $limitKey);
        if ($cap === null) {
            return;
        }
        $used = $this->currentUsage($tenant, $limitKey);
        $threshold = (int) max(1, ceil($cap * 0.8));
        if ($used >= $threshold && $used < $cap) {
            $this->notifier->notifyAlmostReachedIfNeeded($tenant, $limitKey, $used, $cap);
        }
    }

    private function resolvePlanId(Tenant $tenant): ?int
    {
        $tenant->loadMissing('activeSubscription', 'plan');

        return $tenant->activeSubscription?->plan_id ?? $tenant->plan_id;
    }

    private function capFromRow(?\App\Modules\Admin\Tenancy\Models\PlanLimit $row): ?int
    {
        if ($row === null || ! $row->is_enabled) {
            return null;
        }
        if ($row->limit === null) {
            return null;
        }

        return (int) $row->limit;
    }
}
