<?php

declare(strict_types=1);

namespace apexl\Io\modules\user\services\twoFactorAuth\methods;

use apexl\Config\ConfigurationInterface;
use apexl\Io\modules\user\interfaces\TwoFactorMethodInterface;
use RobThree\Auth\Providers\Qr\BaconQrCodeProvider;
use RobThree\Auth\TwoFactorAuth;

/**
 * TOTP (RFC 6238) second factor, backed by robthree/twofactorauth +
 * bacon/bacon-qr-code (SVG backend — pure PHP, no imagick/gd requirement).
 * This is the sole V3.0 method (Plan 007 §1).
 */
final class TotpMethod implements TwoFactorMethodInterface
{
    public const string NAME = 'totp';

    private ?TwoFactorAuth $tfa = null;

    public function __construct(private readonly ConfigurationInterface $config) {}

    public function getMethodName(): string
    {
        return self::NAME;
    }

    public function generateSecret(): string
    {
        return $this->tfa()->createSecret();
    }

    public function provisioningUri(string $accountLabel, string $secret): string
    {
        return $this->tfa()->getQRText($accountLabel, $secret);
    }

    public function qrCodeDataUri(string $accountLabel, string $secret): string
    {
        return $this->tfa()->getQRCodeImageAsDataUri($accountLabel, $secret);
    }

    public function verify(string $secret, string $code, int $discrepancy = 1): bool
    {
        $code = trim($code);
        if ($code === '') {
            return false;
        }

        return $this->tfa()->verifyCode($secret, $code, max(0, $discrepancy));
    }

    private function tfa(): TwoFactorAuth
    {
        if ($this->tfa === null) {
            $issuer = (string) ($this->config->get('auth.two_factor.app_name') ?: 'Cygnus');
            // SVG QR backend keeps this dependency-free (no imagick/gd needed).
            $this->tfa = new TwoFactorAuth(
                new BaconQrCodeProvider(4, '#ffffff', '#000000', 'svg'),
                $issuer,
            );
        }

        return $this->tfa;
    }
}
