package com.expensetracker.api.security.service;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import java.time.Instant;
import java.util.Date;
import javax.crypto.SecretKey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class JwtService {

  private final SecretKey key;
  private final String issuer;
  private final long accessExpiresMinutes;

  public JwtService(
      @Value("${app.jwt.secret}") String secretBase64,
      @Value("${app.jwt.issuer}") String issuer,
      @Value("${app.jwt.access-expires-minutes:${app.jwt.expires-minutes:60}}")
      long accessExpiresMinutes) {

    if (secretBase64 == null || secretBase64.isBlank()) {
      throw new IllegalStateException("Missing required property: app.jwt.secret (base64-encoded).");
    }

    byte[] keyBytes = Decoders.BASE64.decode(secretBase64);

    // Keys.hmacShaKeyFor will throw WeakKeyException if < 256 bits for HS256.
    this.key = Keys.hmacShaKeyFor(keyBytes);

    this.issuer = issuer;
    this.accessExpiresMinutes = accessExpiresMinutes;
  }

  public String createAccessToken(Long userId) {
    Instant now = Instant.now();
    Instant exp = now.plusSeconds(getAccessTokenExpiresInSeconds());

    return Jwts.builder()
        .subject(String.valueOf(userId))
        .issuer(issuer)
        .issuedAt(Date.from(now))
        .expiration(Date.from(exp))
        .signWith(key, Jwts.SIG.HS256)
        .compact();
  }

  public long getAccessTokenExpiresInSeconds() {
    return accessExpiresMinutes * 60;
  }

  public String validateAccessToken(String token) {
    if (token == null || token.isBlank()) {
      throw new IllegalArgumentException("Missing token");
    }

    JwtParser parser = Jwts.parser()
        .verifyWith(key)
        .requireIssuer(issuer)
        .build();

    Jws<Claims> jws = parser.parseSignedClaims(token);
    return jws.getPayload().getSubject();
  }
}
