<?php

namespace App\Services;

use Brick\Math\BigInteger;

class AzerothCoreSrpService
{
    private const string MODULUS_HEX = '894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7';

    private const int GENERATOR = 7;

    private const int BYTE_LENGTH = 32;

    public function normalizeUsername(string $username): string
    {
        return strtoupper(trim($username));
    }

    public function normalizeEmail(string $email): string
    {
        return strtoupper(trim($email));
    }

    public function normalizePassword(string $password): string
    {
        return strtoupper($password);
    }

    /**
     * @return array{0: string, 1: string}
     */
    public function makeRegistrationData(string $username, string $password): array
    {
        $saltHex = strtoupper(bin2hex(random_bytes(self::BYTE_LENGTH)));

        return [$saltHex, $this->makeVerifierHex($username, $password, $saltHex)];
    }

    public function makeVerifierHex(string $username, string $password, string $saltHex): string
    {
        $normalizedUsername = $this->normalizeUsername($username);
        $normalizedPassword = $this->normalizePassword($password);
        $salt = hex2bin($saltHex);

        if ($salt === false) {
            throw new \InvalidArgumentException('Invalid salt hex provided.');
        }

        $innerDigest = hash('sha1', sprintf('%s:%s', $normalizedUsername, $normalizedPassword), true);
        $xDigest = hash('sha1', $salt.$innerDigest, true);
        $modulus = BigInteger::fromBase(self::MODULUS_HEX, 16);
        $exponent = BigInteger::fromBytes(strrev($xDigest), false);
        $verifier = BigInteger::of(self::GENERATOR)->modPow($exponent, $modulus);
        $verifierBytes = strrev(str_pad($verifier->toBytes(false), self::BYTE_LENGTH, "\0", STR_PAD_LEFT));

        return strtoupper(bin2hex($verifierBytes));
    }

    public function credentialsMatch(string $username, string $password, string $saltHex, string $verifierHex): bool
    {
        return hash_equals(
            strtoupper($verifierHex),
            $this->makeVerifierHex($username, $password, $saltHex),
        );
    }
}
