package com.storycove.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import javax.crypto.SecretKey;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Date;

@Component
public class JwtUtil {

    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);

    // Security: Generate new secret on each startup to invalidate all existing tokens
    private String secret;

    @Value("${storycove.jwt.expiration:86400000}") // 24 hours default (access token)
    private Long expiration;

    @Value("${storycove.jwt.refresh-expiration:1209600000}") // 14 days default (refresh token)
    private Long refreshExpiration;

    @PostConstruct
    public void initialize() {
        // Generate a new random secret on startup to invalidate all existing JWT tokens
        // This ensures users must re-authenticate after application restart
        SecureRandom random = new SecureRandom();
        byte[] secretBytes = new byte[64]; // 512 bits
        random.nextBytes(secretBytes);
        this.secret = Base64.getEncoder().encodeToString(secretBytes);

        logger.info("JWT secret rotated on startup - all existing tokens invalidated");
        logger.info("Users will need to re-authenticate after application restart for security");
    }

    public Long getRefreshExpirationMs() {
        return refreshExpiration;
    }

    public String generateRefreshToken() {
        SecureRandom random = new SecureRandom();
        byte[] tokenBytes = new byte[32]; // 256 bits
        random.nextBytes(tokenBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes);
    }
    
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }
    
    public String generateToken() {
        return generateToken("user", null);
    }
    
    public String generateToken(String subject, String libraryId) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration);
        
        var builder = Jwts.builder()
                .subject(subject)
                .issuedAt(now)
                .expiration(expiryDate);
        
        // Add library context if provided
        if (libraryId != null) {
            builder.claim("libraryId", libraryId);
        }
        
        return builder.signWith(getSigningKey()).compact();
    }
    
    public boolean validateToken(String token) {
        try {
            Jwts.parser()
                .verifyWith(getSigningKey())
                .build()
                .parseSignedClaims(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    public Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .verifyWith(getSigningKey())
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }
    
    public boolean isTokenExpired(String token) {
        Date expiration = getClaimsFromToken(token).getExpiration();
        return expiration.before(new Date());
    }
    
    public String getSubjectFromToken(String token) {
        return getClaimsFromToken(token).getSubject();
    }
    
    public String getLibraryIdFromToken(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            return claims.get("libraryId", String.class);
        } catch (Exception e) {
            return null;
        }
    }
}