package de.avatic.lcc.service.apps;

import de.avatic.lcc.model.db.users.App;
import de.avatic.lcc.model.db.users.Group;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;

@Service
public class JwtTokenService {

    private final Key signingKey;
    private final String baseUrl;

    public JwtTokenService(@Value("${jwt.secret}") String secret, @Value("${jwt.issuer}") String baseUrl) {
        this.signingKey = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
        this.baseUrl = baseUrl;
    }


    public String createApplicationToken(App app, long expiration) {

        return Jwts.builder()
                .issuer(baseUrl)
                .subject(app.getClientId())
                .audience().add(baseUrl + "/api").and()
                .issuedAt(new Date())
                .expiration(new Date(System.currentTimeMillis() + (expiration*1000)))
                .claim("client_id", app.getId())
                .claim("groups", app.getGroups().stream().map(Group::getName).toList())
                .claim("token_type", "ext_app")
                .signWith(signingKey)
                .compact();
    }

    public Claims parseClaimsWithoutValidation(String token) {
        try {
            String[] parts = token.split("\\.");

            String payload = parts[1];
            byte[] decodedBytes = java.util.Base64.getUrlDecoder().decode(payload);
            String decodedPayload = new String(decodedBytes, StandardCharsets.UTF_8);

            com.fasterxml.jackson.databind.ObjectMapper mapper =
                    new com.fasterxml.jackson.databind.ObjectMapper();

            @SuppressWarnings("unchecked")
            java.util.Map<String, Object> claimsMap =
                    mapper.readValue(decodedPayload, java.util.Map.class);

            return Jwts.claims().add(claimsMap).build();

        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to parse JWT claims", e);
        }
    }

    public Claims validateToken(String token) {
        return Jwts.parser()
                .verifyWith((SecretKey) signingKey)
                .requireIssuer(baseUrl)
                .requireAudience(baseUrl + "/api")
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }
}