<?php

declare(strict_types=1);

namespace App\Services;

use Illuminate\Database\Capsule\Manager as DB;

class TotpService
{
    // Génère un secret TOTP pour un utilisateur (setup)
    public function genererSecret(): string
    {
        $chars  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
        $secret = '';
        for ($i = 0; $i < 32; $i++) {
            $secret .= $chars[random_int(0, strlen($chars) - 1)];
        }
        return $secret;
    }

    // URL pour QR code Google Authenticator
    public function getQrCodeUrl(string $email, string $secret): string
    {
        $issuer = 'MyKollectOr';
        $label  = urlencode($issuer . ':' . $email);
        return 'otpauth://totp/' . $label
            . '?secret=' . $secret
            . '&issuer=' . urlencode($issuer)
            . '&algorithm=SHA1&digits=6&period=30';
    }

    // Vérifie un code TOTP (fenêtre ±1 période = 90s)
    public function verifierCode(string $secret, string $code): bool
    {
        $code = preg_replace('/\s+/', '', $code);
        if (!preg_match('/^\d{6}$/', $code)) return false;

        $timestamp = (int)floor(time() / 30);

        for ($i = -1; $i <= 1; $i++) {
            if ($this->genererCode($secret, $timestamp + $i) === $code) {
                return true;
            }
        }
        return false;
    }

    private function genererCode(string $secret, int $timestamp): string
    {
        $key     = $this->base32Decode($secret);
        $time    = pack('N*', 0) . pack('N*', $timestamp);
        $hash    = hash_hmac('sha1', $time, $key, true);
        $offset  = ord($hash[19]) & 0x0F;
        $code    = (
            ((ord($hash[$offset])     & 0x7F) << 24) |
            ((ord($hash[$offset + 1]) & 0xFF) << 16) |
            ((ord($hash[$offset + 2]) & 0xFF) << 8) |
             (ord($hash[$offset + 3]) & 0xFF)
        ) % 1000000;

        return str_pad((string)$code, 6, '0', STR_PAD_LEFT);
    }

    private function base32Decode(string $base32): string
    {
        $base32  = strtoupper($base32);
        $chars   = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
        $buffer  = 0;
        $bitsLeft= 0;
        $result  = '';

        for ($i = 0; $i < strlen($base32); $i++) {
            $val = strpos($chars, $base32[$i]);
            if ($val === false) continue;
            $buffer   = ($buffer << 5) | $val;
            $bitsLeft += 5;
            if ($bitsLeft >= 8) {
                $result   .= chr(($buffer >> ($bitsLeft - 8)) & 0xFF);
                $bitsLeft -= 8;
            }
        }
        return $result;
    }

    // Activer 2FA pour un user — retourne le secret et l'URL QR
    public function activer2FA(int $userId, string $email): array
    {
        $secret = $this->genererSecret();
        DB::table('users')->where('id', $userId)->update([
            'totp_secret'  => $secret,
            'totp_enabled' => 0, // Pas encore confirmé
        ]);

        return [
            'secret'     => $secret,
            'qr_url'     => $this->getQrCodeUrl($email, $secret),
            'message'    => 'Scannez le QR code avec Google Authenticator, puis confirmez avec un code.',
        ];
    }

    // Confirmer l'activation — le code doit être valide
    public function confirmer2FA(int $userId, string $code): bool
    {
        $user = DB::table('users')->find($userId);
        if (!$user || !$user->totp_secret) return false;

        if ($this->verifierCode($user->totp_secret, $code)) {
            DB::table('users')->where('id', $userId)->update(['totp_enabled' => 1]);
            return true;
        }
        return false;
    }

    // Désactiver 2FA
    public function desactiver2FA(int $userId): void
    {
        DB::table('users')->where('id', $userId)->update([
            'totp_secret'  => null,
            'totp_enabled' => 0,
        ]);
    }

    // Vérifier si 2FA requis pour ce rôle
    public function estRequis(string $role): bool
    {
        return $role === 'super_admin';
    }
}
