package com.handong.smartservice.JwtAuth;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.util.List;
import java.util.Map;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;


@Component
public class JwtProvider {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //private final long ACCESS_TOKEN_EXPIRE = 1000L * 30; //TestCode 30sec
    //private final long REFRESH_TOKEN_EXPIRE = 1000L * 60 * 2; //TestCode 2min
    private final long ACCESS_TOKEN_EXPIRE = 1000L * 60 * 60; // 60min
    private final long REFRESH_TOKEN_EXPIRE = 1000L * 60 * 60 * 24 * 14; // 14day

    private final Key signingKey;

    private final JwtTokenStore tokenStore;

    public JwtProvider(@Value("${jwt.secret}") String secret) {
        signingKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
        this.tokenStore = new JwtTokenStoreMap();
        //this.tokenStore = new JwtTokenStoreRedis();
    }

    public long getRefreshExpire() {
        return REFRESH_TOKEN_EXPIRE;
    }

    
    /*
    public String createAccessToken(Long gid, String user_id, String nick_name, Long permission, Long biz_group_id) {
        Date now = new Date();
        return Jwts.builder()
            .setSubject(gid.toString())
            .claim("user_id", user_id)
            .claim("nick_name", nick_name)
            .claim("permission", permission)
            .claim("biz_group_id", biz_group_id)
            .setIssuedAt(now)
            .setExpiration(new Date(now.getTime() + ACCESS_TOKEN_EXPIRE))
            .signWith(signingKey, SignatureAlgorithm.HS256)
            .compact();
    }
    */    
    public String createAccessToken(Long gid, Map<String, Object> claims) {
        Date now = new Date();        
        return Jwts.builder()
            .setSubject(gid.toString())
            .addClaims(claims)
            .setIssuedAt(now)
            .setExpiration(new Date(now.getTime() + ACCESS_TOKEN_EXPIRE))
            .signWith(signingKey, SignatureAlgorithm.HS256)
            .compact();
    }

    public String createRefreshToken(Long gid) {
        Date now = new Date();
        String token = Jwts.builder()
            .setSubject(gid.toString())
            .setIssuedAt(now)
            .setExpiration(new Date(now.getTime() + REFRESH_TOKEN_EXPIRE))
            .signWith(signingKey, SignatureAlgorithm.HS256)
            .compact();

        tokenStore.save(gid, token, REFRESH_TOKEN_EXPIRE);
        return token;
    }

    public boolean isValidate(String token) {
        Long gid = 0L;
        try {
            Claims claims = Jwts.parserBuilder()
                .setSigningKey(signingKey)
                .build()
                .parseClaimsJws(token)
                .getBody();

            if (claims.getExpiration().before(new Date()))
                return false;   // expired

            gid = Long.parseLong(claims.getSubject());
            
            String storedToken = tokenStore.get(gid);

            if (storedToken != null && token.compareTo(storedToken) == 0)
                return true;
        }
        catch (ExpiredJwtException e) {
        }

        return false;
    }    

    public Long getGid(String token) {
        String strGid = Jwts.parserBuilder()
            .setSigningKey(signingKey)
            .build()
            .parseClaimsJws(token)
            .getBody()
            .getSubject();

        return Long.parseLong(strGid);
    }

    public Claims getClaims(String token) {
        return Jwts.parserBuilder()
            .setSigningKey(signingKey)
            .build()
            .parseClaimsJws(token)
            .getBody();
    }

    public void delete(Long gid) {
        tokenStore.delete(gid);
    }
}
