package cn.iocoder.yudao.module.system.service.wx;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class WeChatTokenService {

    @Value("${wechat.mp.appid}")
    private String appId;

    @Value("${wechat.mp.appsecret}")
    private String appSecret;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    // 使用 Redis 存储 access_token（如果没有 Redis 可以用本地缓存）
    private static final String ACCESS_TOKEN_KEY = "wechat:access_token";

    private static final String ACCESS_TOKEN_EXPIRES_KEY = "wechat:access_token_expires";

    /**
     * 获取 access_token
     * 先从缓存获取，如果过期或不存在则重新获取
     */
    public String getAccessToken() {
        try {
            // 1. 从 Redis 获取 token
            String token = redisTemplate.opsForValue().get(ACCESS_TOKEN_KEY);
            String expiresTimeStr = redisTemplate.opsForValue().get(ACCESS_TOKEN_EXPIRES_KEY);

            // 2. 检查 token 是否存在且未过期
            if (token != null && expiresTimeStr != null) {
                long expiresTime = Long.parseLong(expiresTimeStr);
                long currentTime = System.currentTimeMillis() / 1000;

                // token 还有效（提前5分钟过期，用于缓冲）
                if (currentTime < expiresTime - 300) {
                    log.info("从缓存获取 access_token: {}", token);
                    return token;
                }
            }

            // 3. 重新获取 token
            log.info("access_token 已过期或不存在，重新获取");
            return fetchAndCacheAccessToken();

        } catch (Exception e) {
            log.error("获取 access_token 异常", e);
            return fetchAndCacheAccessToken(); // 异常时尝试重新获取
        }
    }

    /**
     * 强制刷新并获取新的 access_token
     */
    public String refreshAccessToken() {
        log.info("强制刷新 access_token");
        return fetchAndCacheAccessToken();
    }

    /**
     * 从微信API获取 access_token 并缓存
     */
    private String fetchAndCacheAccessToken() {
        try {
            // 微信 API 地址
            String url = String.format(
                    "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                    appId, appSecret
            );

            log.info("请求微信API获取 access_token，appid: {}", appId);

            // 发送 HTTP 请求
            String response = restTemplate.getForObject(url, String.class);
            log.info("微信API返回: {}", response);

            // 解析响应
            JSONObject json = JSON.parseObject(response);

            // 检查错误
            if (json.containsKey("errcode")) {
                int errorCode = json.getIntValue("errcode");
                String errorMsg = json.getString("errmsg");

                log.error("获取 access_token 失败，错误码: {}, 错误信息: {}", errorCode, errorMsg);

                // 根据错误码处理
                handleAccessTokenError(errorCode, errorMsg);
                return null;
            }

            // 获取 access_token 和过期时间
            String accessToken = json.getString("access_token");
            int expiresIn = json.getIntValue("expires_in"); // 微信返回的是秒数

            if (accessToken == null || accessToken.isEmpty()) {
                log.error("获取的 access_token 为空");
                return null;
            }

            log.info("成功获取 access_token，有效期: {}秒", expiresIn);

            // 计算过期时间（当前时间 + 有效期 - 5分钟缓冲）
            long expireTime = System.currentTimeMillis() / 1000 + expiresIn - 300;

            // 缓存到 Redis
            cacheAccessToken(accessToken, expireTime);

            return accessToken;

        } catch (Exception e) {
            log.error("调用微信API获取 access_token 异常", e);
            return null;
        }
    }

    /**
     * 缓存 access_token 到 Redis
     */
    private void cacheAccessToken(String accessToken, long expireTime) {
        try {
            // 存储 access_token，设置过期时间比微信的有效期短一些
            redisTemplate.opsForValue().set(
                    ACCESS_TOKEN_KEY,
                    accessToken,
                    7000,  // 7000秒 ≈ 1小时56分（比微信的2小时短）
                    TimeUnit.SECONDS
            );

            // 存储过期时间戳
            redisTemplate.opsForValue().set(
                    ACCESS_TOKEN_EXPIRES_KEY,
                    String.valueOf(expireTime),
                    7200,  // 2小时
                    TimeUnit.SECONDS
            );

            log.info("access_token 已缓存到 Redis");

        } catch (Exception e) {
            log.error("缓存 access_token 到 Redis 失败", e);
        }
    }

    /**
     * 处理 access_token 获取错误
     */
    private void handleAccessTokenError(int errorCode, String errorMsg) {
        switch (errorCode) {
            case -1:
                log.error("系统繁忙，请稍候再试");
                break;
            case 40001:
                log.error("AppSecret 错误或者 access_token 无效");
                break;
            case 40002:
                log.error("不合法的凭证类型");
                break;
            case 40013:
                log.error("不合法的 AppID");
                break;
            case 40125:
                log.error("无效的 appsecret");
                break;
            case 45009:
                log.error("接口调用超过限制");
                break;
            default:
                log.error("未知错误，错误码: {}, 错误信息: {}", errorCode, errorMsg);
                break;
        }
    }

    /**
     * 启动时初始化 access_token
     */
//    @PostConstruct
//    public void init() {
//        log.info("初始化 WeChatTokenService，appid: {}", appId);
//
//        // 尝试获取一次 access_token
//        String token = getAccessToken();
//        if (token != null) {
//            log.info("应用启动时成功获取 access_token");
//        } else {
//            log.error("应用启动时获取 access_token 失败");
//        }
//    }

    /**
     * 定时刷新 access_token（每100分钟一次）
     * 微信的 access_token 有效期是2小时（7200秒）
     */
//    @Scheduled(fixedRate = 100 * 60 * 1000) // 100分钟
//    public void scheduledRefreshToken() {
//        log.info("定时刷新 access_token 任务开始");
//
//        try {
//            String token = refreshAccessToken();
//            if (token != null) {
//                log.info("定时刷新 access_token 成功");
//            } else {
//                log.error("定时刷新 access_token 失败");
//            }
//        } catch (Exception e) {
//            log.error("定时刷新 access_token 异常", e);
//        }
//    }

    /**
     * 检查 access_token 是否有效
     */
    public boolean isAccessTokenValid() {
        try {
            String expiresTimeStr = redisTemplate.opsForValue().get(ACCESS_TOKEN_EXPIRES_KEY);
            if (expiresTimeStr == null) {
                return false;
            }

            long expiresTime = Long.parseLong(expiresTimeStr);
            long currentTime = System.currentTimeMillis() / 1000;

            return currentTime < expiresTime;
        } catch (Exception e) {
            log.error("检查 access_token 有效性异常", e);
            return false;
        }
    }

    /**
     * 清除 access_token 缓存
     */
    public void clearAccessToken() {
        try {
            redisTemplate.delete(ACCESS_TOKEN_KEY);
            redisTemplate.delete(ACCESS_TOKEN_EXPIRES_KEY);
            log.info("已清除 access_token 缓存");
        } catch (Exception e) {
            log.error("清除 access_token 缓存异常", e);
        }
    }

    /**
     * 脱敏显示 token（只显示前4位和后4位）
     */
    private String maskToken(String token) {
        if (token == null || token.length() <= 8) {
            return "****";
        }
        return token.substring(0, 4) + "****" + token.substring(token.length() - 4);
    }
}
