package com.zioinfo.kintex.security;

import dev.samstevens.totp.code.DefaultCodeGenerator;
import dev.samstevens.totp.time.SystemTimeProvider;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * TotpService — RFC6238 코드 검증 핵심 로직 단위테스트(외부 리소스 無).
 */
class TotpServiceTest {

    private TotpService newService() {
        SecurityPolicyProperties props = new SecurityPolicyProperties();
        props.getOtp().setIssuer("KINTEX-TEST");
        return new TotpService(props);
    }

    @Test
    void generatesSecretAndVerifiesCurrentCode() throws Exception {
        TotpService svc = newService();
        String secret = svc.generateSecret();
        assertNotNull(secret);
        assertFalse(secret.isBlank());

        // 현재 타임스텝의 정상 코드는 검증 통과해야 한다.
        long currentBucket = new SystemTimeProvider().getTime() / 30;
        String validCode = new DefaultCodeGenerator().generate(secret, currentBucket);
        assertTrue(svc.verify(secret, validCode), "현재 타임스텝 코드는 유효해야 함");
    }

    @Test
    void rejectsWrongCodeAndBlankInputs() {
        TotpService svc = newService();
        String secret = svc.generateSecret();
        assertFalse(svc.verify(secret, "000000"), "임의 코드는 거부");
        assertFalse(svc.verify(secret, ""), "빈 코드는 거부");
        assertFalse(svc.verify(null, "123456"), "시크릿 null 은 거부");
        assertFalse(svc.verify(secret, null), "코드 null 은 거부");
    }

    @Test
    void otpAuthUriContainsIssuerAndSecret() {
        TotpService svc = newService();
        String secret = svc.generateSecret();
        String uri = svc.otpAuthUri(secret, "user@kintex.test");
        assertTrue(uri.startsWith("otpauth://totp/"), "otpauth URI 스킴");
        assertTrue(uri.contains("KINTEX-TEST"), "issuer 포함");
        assertTrue(uri.contains(secret), "secret 포함");
    }
}
