<?php

namespace App\Services;

use App\Models\User;
use App\Models\UserKyc;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;

class IdentityLimitService
{
    /**
     * @param  array<string, mixed>  $identityPayload
     *
     * @throws ValidationException
     */
    public function assertCanCreate(array $identityPayload): void
    {
        $mobile = $this->normalize(Arr::get($identityPayload, 'mobile'));
        $email = $this->normalizeEmail(Arr::get($identityPayload, 'email'));
        $pan = $this->normalize(Arr::get($identityPayload, 'pan_number'));
        $bank = $this->normalize(Arr::get($identityPayload, 'bank_account_number'));

        $errors = [];

        $mobileLimit = $this->limitFor('max_ids_mobile');
        if ($mobile !== null && $mobileLimit !== null && User::query()->where('mobile', $mobile)->count() >= $mobileLimit) {
            $errors['mobile'] = "Maximum {$mobileLimit} IDs allowed per mobile.";
        }

        $emailLimit = $this->limitFor('max_ids_email');
        if ($email !== null && $emailLimit !== null && User::query()->where('email', $email)->count() >= $emailLimit) {
            $errors['email'] = "Maximum {$emailLimit} IDs allowed per email.";
        }

        $panLimit = $this->limitFor('max_ids_pan');
        if ($pan !== null && $panLimit !== null && UserKyc::query()->where('pan_number', $pan)->count() >= $panLimit) {
            $errors['pan_number'] = "Maximum {$panLimit} IDs allowed per PAN.";
        }

        $bankLimit = $this->limitFor('max_ids_bank');
        if ($bank !== null && $bankLimit !== null && UserKyc::query()->where('bank_account_number', $bank)->count() >= $bankLimit) {
            $errors['bank_account_number'] = "Maximum {$bankLimit} IDs allowed per bank account.";
        }

        if ($errors !== []) {
            throw ValidationException::withMessages($errors);
        }
    }

    /**
     * @return int|null Null means unlimited.
     */
    public function maxIdsPerIdentity(): ?int
    {
        $value = strtolower((string) setting('max_ids_per_identity', '3'));

        if ($value === 'unlimited') {
            return null;
        }

        $numeric = (int) $value;

        return $numeric > 0 ? $numeric : 3;
    }

    private function limitFor(string $key): ?int
    {
        $value = setting($key);

        if ($value === null || $value === '') {
            return $this->maxIdsPerIdentity();
        }

        $value = strtolower((string) $value);

        if ($value === 'unlimited') {
            return null;
        }

        $numeric = (int) $value;

        return $numeric > 0 ? $numeric : $this->maxIdsPerIdentity();
    }

    private function normalize(mixed $value): ?string
    {
        if ($value === null) {
            return null;
        }

        $normalized = trim((string) $value);

        return $normalized === '' ? null : strtoupper($normalized);
    }

    private function normalizeEmail(mixed $value): ?string
    {
        if ($value === null) {
            return null;
        }

        $normalized = strtolower(trim((string) $value));

        return $normalized === '' ? null : $normalized;
    }
}

