<?php

namespace App\Core;

/**
 * TOTP (RFC 6238) - للتحقق الثنائي 2FA
 * متوافق مع Google Authenticator و Microsoft Authenticator
 */
class TOTP
{
    private const DIGITS = 6;
    private const PERIOD = 30;

    /**
     * إنشاء سري عشوائي (Base32)
     */
    public static function generateSecret(int $length = 16): string
    {
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
        $secret = '';
        for ($i = 0; $i < $length; $i++) {
            $secret .= $chars[random_int(0, 31)];
        }
        return $secret;
    }

    /**
     * التحقق من رمز TOTP
     */
    public static function verify(string $secret, string $code, int $window = 1): bool
    {
        $code = preg_replace('/\D/', '', $code);
        if (strlen($code) !== self::DIGITS) return false;

        $time = floor(time() / self::PERIOD);
        for ($i = -$window; $i <= $window; $i++) {
            if (self::getCode($secret, $time + $i) === $code) {
                return true;
            }
        }
        return false;
    }

    /**
     * الحصول على الكود الحالي
     */
    public static function getCode(string $secret, ?int $timestamp = null): string
    {
        $time = $timestamp ?? floor(time() / self::PERIOD);
        $secretBinary = self::base32Decode($secret);
        $timeBytes = pack('N*', 0) . pack('N', $time);
        $hash = hash_hmac('sha1', $timeBytes, $secretBinary, true);
        $offset = ord($hash[strlen($hash) - 1]) & 0x0F;
        $value = (
            ((ord($hash[$offset]) & 0x7F) << 24) |
            ((ord($hash[$offset + 1]) & 0xFF) << 16) |
            ((ord($hash[$offset + 2]) & 0xFF) << 8) |
            (ord($hash[$offset + 3]) & 0xFF)
        );
        $otp = $value % pow(10, self::DIGITS);
        return str_pad((string)$otp, self::DIGITS, '0', STR_PAD_LEFT);
    }

    private static function base32Decode(string $secret): string
    {
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
        $secret = strtoupper($secret);
        $buffer = 0;
        $bitsLeft = 0;
        $output = '';
        for ($i = 0; $i < strlen($secret); $i++) {
            $pos = strpos($chars, $secret[$i]);
            if ($pos === false) continue;
            $buffer = ($buffer << 5) | $pos;
            $bitsLeft += 5;
            if ($bitsLeft >= 8) {
                $bitsLeft -= 8;
                $output .= chr(($buffer >> $bitsLeft) & 0xFF);
            }
        }
        return $output;
    }

    /**
     * رابط otpauth لإنشاء QR
     */
    public static function getProvisioningUri(string $secret, string $account, string $issuer = 'Smart Doctor'): string
    {
        $params = [
            'secret' => $secret,
            'issuer' => $issuer,
            'algorithm' => 'SHA1',
            'digits' => self::DIGITS,
            'period' => self::PERIOD
        ];
        $label = rawurlencode($issuer . ':' . $account);
        $query = http_build_query($params);
        return 'otpauth://totp/' . $label . '?' . $query;
    }
}
