package com.tangguo.common.mauth;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 移动端用户Token处理
 *
 * @author 谈笑
 * @createTime 2025-09-02 14:42:17 星期二
 */
@Component
public class MobileTokenHelper {

	private static MobileProperties properties;


	@Resource
	public void setProperties(MobileProperties properties) {
		MobileTokenHelper.properties = properties;
	}


	/**
	 * 计算Token过期时间
	 *
	 * @return Token过期时间
	 */
	private static Date getTokenExpiredTime() {
		return Date.from(Instant.now().plus(properties.getEffectiveTime()));
	}


	/**
	 * 获取Token签名器
	 *
	 * @return Token签名器
	 */
	private static JWTSigner getTokenSigner() {
		return JWTSignerUtil.createSigner(
			properties.getAlgorithmId(), properties.getSignKey().getBytes()
		);
	}


	/**
	 * 构建JWT实体 (只填充了关键参数，并未签名。)
	 *
	 * @return JWT实体
	 */
	private static JWT buildJWT() {
		JWT jwtToken = JWT.create();
		jwtToken.setIssuer(properties.getIssuer());
		jwtToken.setIssuedAt(new Date());
		jwtToken.setExpiresAt(getTokenExpiredTime());
		jwtToken.setSigner(getTokenSigner());
		return jwtToken;
	}


	/**
	 * 创建Token
	 *
	 * @param payloads 荷载参数
	 * @return Token字符串
	 */
	public static String createToken(Map<String, Object> payloads) {
		JWT jwtToken = buildJWT();
		if (MapUtil.isNotEmpty(payloads)) {
			payloads.forEach(jwtToken::setPayload);
		}
		return jwtToken.sign();
	}


	/**
	 * 创建Token，并返回Token明细信息。
	 *
	 * @param payloads 荷载参数
	 * @return Token字符串
	 */
	public static Map<String, Object> createDetailToken(Map<String, Object> payloads) {
		String token = createToken(payloads);
		Map<String, Object> detailTokenMap = new LinkedHashMap<>(2);
		detailTokenMap.put(properties.getResTokenName(), token);
		detailTokenMap.put("expiredTime", DateUtil.formatDateTime(getTokenExpiredTime()));
		return detailTokenMap;
	}


    /**
     * 获取当前用户Token
     *
     * @return 用户Token
     */
    public static String getCurrentToken() {
        try {
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
            if (Objects.isNull(requestAttributes)) {
                return null;
            }
            HttpServletRequest request = requestAttributes.getRequest();
            String tokenValue = request.getHeader(properties.getReqTokenName());
            if (tokenValue.startsWith("Bearer")) {
                tokenValue = tokenValue.replace("Bearer ", "");
            }
            return tokenValue;
        } catch (Exception e) {
            return null;
        }
    }


	/**
	 * 验证Token
	 *
	 * @param token Token字符串
	 * @return 验证结果
	 */
	public static boolean verifyToken(String token) {
		if (StrUtil.isBlank(token)) {
			return false;
		}
		try {
			// 验证Token的签名和时效
			return JWT.of(token).setSigner(getTokenSigner()).validate(0L);
		} catch (Exception e) {
			return false;
		}
	}


	/**
	 * 校验Token
	 *
	 * @param token Token字符串
	 */
	public static JWT verifyParseToken(String token) {
		if (StrUtil.isBlank(token)) {
			throw new Mobile401Exception("身份认证失败，未获取到用户认证信息。");
		}
		try {
			// 验证Token的签名和时效
			JWTValidator.of(token).validateAlgorithm(getTokenSigner()).validateDate();
			return JWT.of(token);
		} catch (Exception e) {
			throw new Mobile401Exception("身份认证失败，当前用户认证信息已失效或已过期。");
		}
	}


	/**
	 * 获取当前用户Token荷载信息
	 *
	 * @return Token荷载信息
	 */
	public static JSONObject getTokenPayloads() {
		return verifyParseToken(getCurrentToken()).getPayloads();
	}


	/**
	 * 获取当前用户名
	 *
	 * @return 用户名
	 */
	public static String getUsername() {
		try {
			String username = getTokenPayloads().getStr("userName");
			if (StrUtil.isNotBlank(username)) {
				return username;
			} else {
				throw new Mobile401Exception("身份认证失败，未获取到当前用户身份信息。");
			}
		} catch (Mobile401Exception e) {
			throw e;
		} catch (Exception e) {
			throw new Mobile401Exception("获取当前用户身份信息获取失败。");
		}
	}

}
