package com.oqpo.api.config;

import com.oqpo.api.constant.ApiConstants;
import com.oqpo.api.web.dto.response.token.TokenResponse;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;

@RequiredArgsConstructor
@Component
public class JwtTokenProvider { // JWT 토큰을 생성 및 검증 모듈
    @Value("${spring.jwt.secret}")
    private String secretKey;

    @PostConstruct
    protected void init() {
        secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
    }

    // Jwt 토큰 생성
    public String createToken(String mId, String userNm, String systemAdminYn, String authTpCd, Boolean isLogin, String afflShopId, String brandId, String authTpNm) {

        Claims claims = Jwts.claims().setSubject(mId);
        claims.put(ApiConstants.CLAIMS_USER_NM, userNm);
        claims.put(ApiConstants.CLAIMS_SYSTEM_ADMIN_YN, systemAdminYn);
        claims.put(ApiConstants.CLAIMS_AUTH_TP_CD, authTpCd);
        claims.put(ApiConstants.CLAIMS_IS_LOGIN, isLogin);
        claims.put(ApiConstants.CLAIMS_AFFL_SHOP_ID,afflShopId );
        claims.put(ApiConstants.CLAIMS_BRAND_ID,brandId );
        claims.put(ApiConstants.CLAIMS_AUTH_TP_NM, authTpNm);

        Date now = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(now);
        cal.add(Calendar.HOUR, 24);
        return Jwts.builder()
                .setClaims(claims) // 데이터
                .setIssuedAt(now) // 토큰 발행일자
                .setExpiration(cal.getTime()) // set Expire Time
                .signWith(SignatureAlgorithm.HS256, secretKey) // 암호화 알고리즘, secret값 세팅
                .compact();
    }

    // Jwt 토큰에서 사용자ID 정보
    public String getUserId(String token) {
        return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
    }

    // Jwt 토큰에서 사용자명 정보
    public String getUserNm(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return (String)claims.getBody().get(ApiConstants.CLAIMS_USER_NM);
    }


    // Jwt 토큰에서 시스템 관리자 여부 정보
    public String getSystemAdminYn(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return (String)claims.getBody().get(ApiConstants.CLAIMS_SYSTEM_ADMIN_YN);
    }

    // Jwt 토큰에서 사용자 타입 정보
    public String getAuthTpCd(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return (String)claims.getBody().get(ApiConstants.CLAIMS_AUTH_TP_CD);
    }

    // Jwt 토큰에서 로그인 구별 정보
    public Boolean isLogin(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return (Boolean)claims.getBody().get(ApiConstants.CLAIMS_IS_LOGIN);
    }

    // Jwt 토큰에서 소속 가맹점 타입 정보
    public String getAfflShopId(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return (String)claims.getBody().get(ApiConstants.CLAIMS_AFFL_SHOP_ID);
    }

    // Jwt 토큰에서 소속 브랜드 타입 정보
    public String getBrandId(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return (String)claims.getBody().get(ApiConstants.CLAIMS_BRAND_ID);
    }

    // Jwt 토큰에서 사용자 타입 정보
    public String getAuthTpNm(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return (String)claims.getBody().get(ApiConstants.CLAIMS_AUTH_TP_NM);
    }

    public TokenResponse getTokenInfo(String token) {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        return TokenResponse.toDTO(claims);
    }

    // Request의 Header에서 token 파싱 : "X-AUTH-TOKEN: jwt토큰"
    public String resolveToken(HttpServletRequest req) {
        return req.getHeader(ApiConstants.AUTH_TOKEN);
    }

    // Jwt 토큰의 유효성 + 만료일자 확인
    public boolean validateToken(String jwtToken) {
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
            return !claims.getBody().getExpiration().before(new Date());
        } catch (Exception e) {
            return false;
        }
    }
}