package tech.sud.mgp.auth.api;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.Objects;

/**
 * Minimal in-repo replacement for the original SUD auth SDK.
 * The project only uses round-trip code generation and verification on our own backend,
 * so a signed JWT is enough to preserve the current integration flow.
 */
public class SudMGPAuth {
    private static final String CLAIM_UID = "uid";
    private static final String CLAIM_TYPE = "type";
    private static final String TOKEN_TYPE_CODE = "code";
    private static final int ERROR_INVALID_TOKEN = 10001;
    private static final int ERROR_TOKEN_EXPIRED = 10002;
    private static final int ERROR_INVALID_ARGUMENT = 10003;
    private static final long DEFAULT_EXPIRE_MILLIS = 24 * 60 * 60 * 1000L;

    private final String appId;
    private final Algorithm algorithm;
    private final JWTVerifier codeVerifier;

    public SudMGPAuth(String appId, String appSecret) {
        this.appId = appId;
        this.algorithm = Algorithm.HMAC256(appSecret);
        this.codeVerifier = JWT.require(algorithm)
                .withIssuer(appId)
                .withClaim(CLAIM_TYPE, TOKEN_TYPE_CODE)
                .build();
    }

    public SudCode getCode(String uid, Long expireDuration) {
        if (uid == null || uid.isBlank()) {
            return new SudCode(null, null, false, ERROR_INVALID_ARGUMENT);
        }
        long expireMillis = System.currentTimeMillis() + normalizedExpire(expireDuration);
        String code = JWT.create()
                .withIssuer(appId)
                .withIssuedAt(new Date())
                .withExpiresAt(new Date(expireMillis))
                .withClaim(CLAIM_UID, uid)
                .withClaim(CLAIM_TYPE, TOKEN_TYPE_CODE)
                .sign(algorithm);
        return new SudCode(code, expireMillis, true, 0);
    }

    public SudUid getUidByCode(String code) {
        if (code == null || code.isBlank()) {
            return new SudUid(null, false, ERROR_INVALID_ARGUMENT);
        }
        try {
            DecodedJWT decodedJWT = codeVerifier.verify(code);
            String uid = decodedJWT.getClaim(CLAIM_UID).asString();
            if (uid == null || uid.isBlank()) {
                return new SudUid(null, false, ERROR_INVALID_TOKEN);
            }
            return new SudUid(uid, true, 0);
        } catch (com.auth0.jwt.exceptions.TokenExpiredException ex) {
            return new SudUid(null, false, ERROR_TOKEN_EXPIRED);
        } catch (JWTVerificationException ex) {
            return new SudUid(null, false, ERROR_INVALID_TOKEN);
        }
    }

    public boolean verifyCode(String code) {
        return getUidByCode(code).isSuccess();
    }

    private static long normalizedExpire(Long expireDuration) {
        if (Objects.isNull(expireDuration) || expireDuration <= 0) {
            return DEFAULT_EXPIRE_MILLIS;
        }
        return expireDuration;
    }
}
