package com.zioinfo.kintex.security;

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자리) 2차 인증 — WISE/UIWS TotpService 이식.
 * 시크릿(app_user.otp_secret)은 응답/로그 노출 금지(계약 §0-3). ±1 윈도우 허용(시계 오차).
 */
@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 final String issuer;

    public TotpService(SecurityPolicyProperties props) {
        this.issuer = props.getOtp().getIssuer();
    }

    private CodeVerifier buildVerifier() {
        DefaultCodeVerifier verifier = new DefaultCodeVerifier(codeGenerator, timeProvider);
        verifier.setTimePeriod(30);
        verifier.setAllowedTimePeriodDiscrepancy(1);
        return verifier;
    }

    /** 신규 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 userLabel) {
        return buildQrData(secret, userLabel).getUri();
    }

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

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