package cz.senslog.connector.tools.jwt;

import cz.senslog.connector.tools.json.BasicJson;
import cz.senslog.connector.tools.util.Tuple;

import java.util.Base64;
import java.util.Map;
import java.util.stream.Collectors;

import static cz.senslog.connector.tools.json.BasicJson.jsonToObject;

public class JWTDecoder {

    static class Header {
        String alg, typ;
    }

    public static JWToken decodeJWT(String jwtToken) {
        try {
            String[] parts = jwtToken.split("\\.");
            if (parts.length != 3) {
                throw new IllegalArgumentException("Invalid JWT token format.");
            }

            Header header = jsonToObject(new String(Base64.getUrlDecoder().decode(parts[0])), Header.class);
            String decodedPayload = new String(Base64.getUrlDecoder().decode(parts[1]));
            Map<String, JWClaim> payloadMap = BasicJson.<Map<String, Object>>jsonToObject(decodedPayload, Map.class)
                    .entrySet().stream().map(e -> Tuple.of(e.getKey(), new JWClaim(e.getValue())))
                    .collect(Collectors.toMap(Tuple::getItem1, Tuple::getItem2));
            String signature = parts[2];

            JWTPayload payload = new JWTPayload(
                    payloadMap.containsKey("sub") ? payloadMap.remove("sub").getAsString() : null,
                    payloadMap.containsKey("iss") ? payloadMap.remove("iss").getAsString() : null,
                    payloadMap.containsKey("aud") ? payloadMap.remove("aud").getAsString() : null,
                    payloadMap.containsKey("exp") ? payloadMap.remove("exp").getAsLong() : 0L ,
                    payloadMap.containsKey("iat") ? payloadMap.remove("iat").getAsLong() : 0L ,
                    payloadMap.containsKey("jti") ? payloadMap.remove("jti").getAsString() : null,
                    payloadMap
            );

            return new JWToken(jwtToken, new JWTHeader(header), payload, signature);
        } catch (Exception e) {
            System.err.println("Error decoding JWT: " + e.getMessage());
        }

        return null;
    }
}