package com.bb.jwt;


import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.Getter;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

import com.bb.jwt.JwtManager.TokenInfo;

public class JwtManager {
    private String secretKey;
    private long TOKEN_VALIDATiON_SECOND;
    private long ADMIN_VALIDATiON_SECOND = 60;
    private long ADMIN_VALIDATiON_SECOND_REFRESH = 6000;

    public JwtManager(String secretKey, long TOKEN_VALIDATiON_SECOND) {
        this.secretKey = secretKey;
        this.TOKEN_VALIDATiON_SECOND = TOKEN_VALIDATiON_SECOND;
    }

    // secretKey 로드
    private Key getSigninKey() {
        byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
        return Keys.hmacShaKeyFor(keyBytes);
    }

    // 토큰 생성
    public String generateToken(JwtClame jwtinfo) {
        Claims claims = Jwts.claims();
        claims.put("mid", jwtinfo.getMemId());
        claims.put("sid", jwtinfo.getSiteId());
        claims.put("type", jwtinfo.getType());

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + (TOKEN_VALIDATiON_SECOND * 1000)))
                .signWith(getSigninKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    // 토큰 생성 5일
    public String generateToken2(JwtClame jwtinfo) {
        Claims claims = Jwts.claims();
        claims.put("mid", jwtinfo.getMemId());
        claims.put("sid", jwtinfo.getSiteId());
        claims.put("type", jwtinfo.getType());
        
        long fiveDays = 5L * 24 * 60 * 60 * 1000; // 5일 밀리초
        
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        long currentTMS = System.currentTimeMillis();
        Date issuedAt = new Date(currentTMS);
        String issuedAtStr = sdf.format(issuedAt);
        Date expiration = new Date(currentTMS + fiveDays);
        String expirationStr = sdf.format(expiration);
        
        System.out.println("[JwtManager.generateToken(jwtinfo)] sid: " + jwtinfo.getSiteId());
        System.out.println("[JwtManager.generateToken(jwtinfo)] mid: " + jwtinfo.getMemId());
        System.out.println("[JwtManager.generateToken(jwtinfo)] IAT: " + issuedAtStr);
        System.out.println("[JwtManager.generateToken(jwtinfo)] EAT: " + expirationStr);
        System.out.println("#-JwtManager::generateToken::admin::"+jwtinfo.getSiteId()+"::"+jwtinfo.getMemId()+"::IAT::"+issuedAtStr+"::EAT::"+expirationStr);

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(issuedAt)
                .setExpiration(expiration)
                .signWith(getSigninKey(), SignatureAlgorithm.HS256)
                .compact();
    }
    
    
    // 토큰 생성
    public String generateTokenAdmin(JwtClame jwtinfo) {
        Claims claims = Jwts.claims();
        claims.put("sid", jwtinfo.getSiteId());     
        claims.put("type", "A");
        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + (TOKEN_VALIDATiON_SECOND * 6000)))
                .signWith(getSigninKey(), SignatureAlgorithm.HS256)
                .compact();
    }
    
    // 토큰 생성
    public String generateTokenRefresh(JwtClame jwtinfo) {
        Claims claims = Jwts.claims();
        claims.put("sid", jwtinfo.getSiteId());     
        claims.put("type", "R"); 
       
        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + (TOKEN_VALIDATiON_SECOND * 240000)))
                .signWith(getSigninKey(), SignatureAlgorithm.HS256)
                .compact();
    }

    // 토큰 정보 리턴
    public TokenInfo getTokenInfo(String token) {
        Claims body = getClaims(token);
        Set<String> keySet = body.keySet();
        for (String s : keySet) {
            // System.out.println("s = " + s);
        }

        String mid = body.get("mid", String.class);
        String sid = body.get("sid", String.class);
        String type = body.get("type", String.class);
        Date issuedAt = body.getIssuedAt();
        Date expiration = body.getExpiration();
        return new TokenInfo(sid, mid, type,  issuedAt, expiration);
    }
    
    // 토큰 정보 리턴
    public TokenInfo getTokenInfoAdmin(String token) {
    	
    	
        Claims body = getClaims(token);
        String type = body.get("type", String.class);
        if("A".equals(type)) {
	        
	        Set<String> keySet = body.keySet();
	        for (String s : keySet) {
	            // System.out.println("s = " + s);
	        }
	      
	        String sid = body.get("sid", String.class);
	      
	        Date issuedAt = body.getIssuedAt();
	        Date expiration = body.getExpiration();
	        return new TokenInfo(sid, null, type,  issuedAt, expiration);
        }else {
        	return null;
        }
    }

    // 토큰정보 해석
    private Claims getClaims(String token) {
        Claims body = Jwts.parserBuilder()
                .setSigningKey(getSigninKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
        return body;
    }


    @Getter
    public class TokenInfo {
        private String mid;
        private String sid;
        private String type;
        private Date issuedAt;
        private Date expire;

        public TokenInfo(String sid, String mid, String type,  Date issuedAt, Date expire) {
            this.sid = sid;
            this.mid = mid;
            this.type = type;
            this.issuedAt = issuedAt;
            this.expire = expire;
        }

		@Override
		public String toString() {
			return "TokenInfo [mid=" + mid + ", sid=" + sid + ", type=" + type + ", issuedAt=" + issuedAt + ", expire=" + expire + "]";
		}
        
    }
}
