package study.gateway;

import java.time.Instant;
import java.util.Date;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import com.nimbusds.jwt.*;

/** Local signed credentials for a resource-server boundary; not OAuth issuance or an IdP. */
public class JwtMaterial {
    private final RSAKey key;
    public JwtMaterial() throws Exception { key=new RSAKeyGenerator(2048).keyID("u32-local").generate(); }
    java.security.interfaces.RSAPublicKey publicKey() throws JOSEException { return key.toRSAPublicKey(); }
    String token(String variant) throws Exception {
        var claims=new JWTClaimsSet.Builder().issuer(variant.equals("issuer")?"https://untrusted.invalid":"https://issuer.example.test")
                .audience(variant.equals("audience")?"other-api":"u32-api").subject(variant.equals("bob")?"bob":variant.equals("carol")?"carol":"alice")
                .expirationTime(Date.from(Instant.now().plusSeconds(variant.equals("expired")?-120:120)))
                .claim("scope",variant.equals("scope")?"other":variant.equals("ops")?"ops":"read").build();
        var token=new SignedJWT(new JWSHeader(JWSAlgorithm.RS256),claims);
        token.sign(new RSASSASigner(variant.equals("signature")?new RSAKeyGenerator(2048).generate():key));
        return token.serialize();
    }
    String downstreamSubject(String authorization) throws Exception {
        if(authorization==null||!authorization.startsWith("Bearer "))throw new IllegalArgumentException("missing bearer");
        var token=SignedJWT.parse(authorization.substring(7));
        var claims=token.getJWTClaimsSet();
        if(!token.verify(new RSASSAVerifier(publicKey()))||!"https://issuer.example.test".equals(claims.getIssuer())
                ||!claims.getAudience().contains("u32-api")||claims.getExpirationTime()==null
                ||!claims.getExpirationTime().toInstant().isAfter(Instant.now()))throw new IllegalArgumentException("invalid bearer");
        if(!"read".equals(claims.getStringClaim("scope")))throw new IllegalArgumentException("missing scope");
        return claims.getSubject();
    }
}
