package com.zioinfo.hrm.uiws.auth;

import dev.samstevens.totp.code.CodeGenerator;
import dev.samstevens.totp.code.CodeVerifier;
import dev.samstevens.totp.code.DefaultCodeGenerator;
import dev.samstevens.totp.code.DefaultCodeVerifier;
import dev.samstevens.totp.code.HashingAlgorithm;
import dev.samstevens.totp.exceptions.QrGenerationException;
import dev.samstevens.totp.qr.QrData;
import dev.samstevens.totp.qr.QrGenerator;
import dev.samstevens.totp.qr.ZxingPngQrGenerator;
import dev.samstevens.totp.secret.DefaultSecretGenerator;
import dev.samstevens.totp.secret.SecretGenerator;
import dev.samstevens.totp.time.SystemTimeProvider;
import dev.samstevens.totp.time.TimeProvider;
import dev.samstevens.totp.util.Utils;
import org.springframework.stereotype.Service;

/**
 * TOTP(RFC 6238, HMAC-SHA1, 30s, 6자리, ±1 윈도우) 코덱 — UIWS TotpService 미러.
 * 시크릿(otp_secret)은 hrm_users 에 저장되어 있다고 가정. issuer 만 GUARDiA-HRM 으로 교체.
 *
 * <p>보안 불변: 시크릿·otpauth URI·QR 은 등록 순간 발급 응답에서만 노출. 로그 기록 금지.
 */
@Service
public class TotpService {

    private final TimeProvider timeProvider = new SystemTimeProvider();
    private final CodeGenerator codeGenerator = new DefaultCodeGenerator(HashingAlgorithm.SHA1, 6);
    private final SecretGenerator secretGenerator = new DefaultSecretGenerator();
    private final CodeVerifier codeVerifier = buildVerifier();
    private final QrGenerator qrGenerator = new ZxingPngQrGenerator();

    private static final String ISSUER = "GUARDiA-HRM";

    private CodeVerifier buildVerifier() {
        DefaultCodeVerifier verifier = new DefaultCodeVerifier(codeGenerator, timeProvider);
        verifier.setTimePeriod(30);
        verifier.setAllowedTimePeriodDiscrepancy(1); // ±1 윈도우 허용(시계 오차)
        return verifier;
    }

    /** 신규 OTP 시크릿 생성(최초 로그인/마이페이지 OTP 등록용). */
    public String generateSecret() {
        return secretGenerator.generate();
    }

    /** 주어진 시크릿에 대해 사용자 입력 코드가 유효한지 검증. */
    public boolean verify(String secret, String code) {
        if (secret == null || secret.isBlank() || code == null || code.isBlank()) {
            return false;
        }
        return codeVerifier.isValidCode(secret, code.trim());
    }

    /** Authenticator 앱 직접 등록용 otpauth:// URI. */
    public String otpAuthUri(String secret, String userId) {
        return buildQrData(secret, userId).getUri();
    }

    /** QR 이미지(data:image/png;base64,...) — 앱으로 스캔해 등록. */
    public String qrImageDataUri(String secret, String userId) {
        try {
            byte[] image = qrGenerator.generate(buildQrData(secret, userId));
            return Utils.getDataUriForImage(image, qrGenerator.getImageMimeType());
        } catch (QrGenerationException e) {
            throw new IllegalStateException("OTP QR 생성 실패", e);
        }
    }

    private QrData buildQrData(String secret, String userId) {
        return new QrData.Builder()
                .label(userId)
                .secret(secret)
                .issuer(ISSUER)
                .algorithm(HashingAlgorithm.SHA1)
                .digits(6)
                .period(30)
                .build();
    }
}
