package com.gxwebsoft.common.system.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * 微信公共服务类
 * 
 * @author 科技小王子
 * @since 2025-09-08
 */
@Slf4j
@Service
public class WxService {

    @Autowired
    private SettingService settingService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String ACCESS_TOKEN_KEY = "WX_ACCESS_TOKEN";
    private static final String MP_OFFICIAL_ACCESS_TOKEN_KEY = "MP_OFFICIAL_ACCESS_TOKEN";

    /**
     * 获取微信AccessToken（使用默认租户）
     */
    public String getAccessToken() {
        return getAccessToken(null);
    }

    /**
     * 获取微信AccessToken（支持指定租户ID）
     * 
     * @param tenantId 租户ID，为null时使用默认值
     * @return access_token
     */
    public String getAccessToken(Integer tenantId) {
        if (tenantId == null) {
            tenantId = 10048; // 默认租户ID，可以根据需要调整
        }
        
        String key = ACCESS_TOKEN_KEY + ":" + tenantId;
        
        // 从缓存获取
        String cachedToken = redisTemplate.opsForValue().get(key);
        if (StrUtil.isNotBlank(cachedToken)) {
            try {
                JSONObject tokenData = JSON.parseObject(cachedToken);
                String accessToken = tokenData.getString("access_token");
                if (StrUtil.isNotBlank(accessToken)) {
                    log.debug("从缓存获取access_token: {}", accessToken);
                    return accessToken;
                }
            } catch (Exception e) {
                // 解析失败，可能是旧格式，直接使用
                if (!cachedToken.startsWith("{")) {
                    log.debug("从缓存获取access_token(旧格式): {}", cachedToken);
                    return cachedToken;
                }
                log.warn("解析缓存的access_token失败: {}", e.getMessage());
                // 缓存数据异常，删除缓存，重新获取
                redisTemplate.delete(key);
            }
        }

        // 缓存中没有，重新获取
        try {
            JSONObject setting = settingService.getBySettingKey("mp-weixin");
            if (setting == null) {
                throw new RuntimeException("请先配置微信小程序");
            }

            String appId = setting.getString("appId");
            String appSecret = setting.getString("appSecret");
            if (StrUtil.isBlank(appId) || StrUtil.isBlank(appSecret)) {
                throw new RuntimeException("微信小程序配置不完整");
            }

            // 调用微信API获取AccessToken
            String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" 
                + appId + "&secret=" + appSecret;
            String response = HttpRequest.get(apiUrl).execute().body();
            
            JSONObject result = JSON.parseObject(response);
            String accessToken = result.getString("access_token");
            if (StrUtil.isNotBlank(accessToken)) {
                // 存入缓存
                JSONObject tokenData = new JSONObject();
                tokenData.put("access_token", accessToken);
                tokenData.put("expires_in", result.get("expires_in"));
                redisTemplate.opsForValue().set(key, tokenData.toJSONString(), 7000L, TimeUnit.SECONDS);
                log.info("获取新的access_token成功: {}", accessToken);
                return accessToken;
            } else {
                throw new RuntimeException("获取AccessToken失败: " + response);
            }
        } catch (Exception e) {
            log.error("获取微信AccessToken失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取微信AccessToken失败: " + e.getMessage());
        }
    }

    /**
     * 强制刷新微信AccessToken（先删除缓存，再重新获取）
     * 用于当 token 过期或失效后，需要强制获取新 token 的场景
     *
     * @param tenantId 租户ID，为null时使用默认值
     * @return access_token
     */
    public String getAccessTokenForcibly(Integer tenantId) {
        if (tenantId == null) {
            tenantId = 10048;
        }

        String key = ACCESS_TOKEN_KEY + ":" + tenantId;

        // 先删除缓存
        redisTemplate.delete(key);
        log.info("强制刷新access_token，已删除缓存: {}", key);

        // 直接从微信API获取新token（不再检查缓存）
        try {
            JSONObject setting = settingService.getBySettingKey("mp-weixin");
            if (setting == null) {
                throw new RuntimeException("请先配置微信小程序");
            }

            String appId = setting.getString("appId");
            String appSecret = setting.getString("appSecret");
            if (StrUtil.isBlank(appId) || StrUtil.isBlank(appSecret)) {
                throw new RuntimeException("微信小程序配置不完整");
            }

            // 调用微信API获取AccessToken
            String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                + appId + "&secret=" + appSecret;
            String response = HttpRequest.get(apiUrl).execute().body();

            JSONObject result = JSON.parseObject(response);
            String accessToken = result.getString("access_token");
            if (StrUtil.isNotBlank(accessToken)) {
                // 存入缓存
                JSONObject tokenData = new JSONObject();
                tokenData.put("access_token", accessToken);
                tokenData.put("expires_in", result.get("expires_in"));
                redisTemplate.opsForValue().set(key, tokenData.toJSONString(), 7000L, TimeUnit.SECONDS);
                log.info("强制刷新access_token成功: {}", accessToken);
                return accessToken;
            } else {
                throw new RuntimeException("获取AccessToken失败: " + response);
            }
        } catch (Exception e) {
            log.error("强制刷新微信AccessToken失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取微信AccessToken失败: " + e.getMessage());
        }
    }

    /**
     * 获取微信公众号 AppID
     */
    public String getOfficialAppId() {
        return getOfficialAppId(null);
    }

    /**
     * 获取微信公众号 AppID（支持指定租户ID）
     */
    public String getOfficialAppId(Integer tenantId) {
        if (tenantId == null) {
            tenantId = 10048;
        }
        JSONObject setting = settingService.getBySettingKey("wx-official");
        if (setting == null) {
            throw new RuntimeException("请先配置微信公众号");
        }
        String appId = setting.getString("appId");
        if (StrUtil.isBlank(appId)) {
            throw new RuntimeException("微信公众号配置不完整");
        }
        return appId;
    }

    /**
     * 获取微信公众号 AppSecret
     */
    public String getOfficialAppSecret() {
        return getOfficialAppSecret(null);
    }

    /**
     * 获取微信公众号 AppSecret（支持指定租户ID）
     */
    public String getOfficialAppSecret(Integer tenantId) {
        if (tenantId == null) {
            tenantId = 10048;
        }
        JSONObject setting = settingService.getBySettingKey("wx-official");
        if (setting == null) {
            throw new RuntimeException("请先配置微信公众号");
        }
        String appSecret = setting.getString("appSecret");
        if (StrUtil.isBlank(appSecret)) {
            throw new RuntimeException("微信公众号配置不完整");
        }
        return appSecret;
    }

    /**
     * 获取微信公众号 AccessToken（用于 API 调用，非用户授权）
     */
    public String getOfficialAccessToken() {
        return getOfficialAccessToken(null);
    }

    /**
     * 获取微信公众号 AccessToken（支持指定租户ID）
     */
    public String getOfficialAccessToken(Integer tenantId) {
        if (tenantId == null) {
            tenantId = 10048;
        }
        
        String key = MP_OFFICIAL_ACCESS_TOKEN_KEY + ":" + tenantId;
        
        // 从缓存获取
        String cachedToken = redisTemplate.opsForValue().get(key);
        if (StrUtil.isNotBlank(cachedToken)) {
            try {
                JSONObject tokenData = JSON.parseObject(cachedToken);
                String accessToken = tokenData.getString("access_token");
                if (StrUtil.isNotBlank(accessToken)) {
                    log.debug("从缓存获取公众号access_token: {}", accessToken);
                    return accessToken;
                }
            } catch (Exception e) {
                log.warn("解析缓存的公众号access_token失败: {}", e.getMessage());
                redisTemplate.delete(key);
            }
        }

        // 缓存中没有，重新获取
        try {
            String appId = getOfficialAppId(tenantId);
            String appSecret = getOfficialAppSecret(tenantId);

            String apiUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" 
                + appId + "&secret=" + appSecret;
            String response = HttpUtil.get(apiUrl);
            
            JSONObject result = JSON.parseObject(response);
            String accessToken = result.getString("access_token");
            if (StrUtil.isNotBlank(accessToken)) {
                JSONObject tokenData = new JSONObject();
                tokenData.put("access_token", accessToken);
                tokenData.put("expires_in", result.get("expires_in"));
                redisTemplate.opsForValue().set(key, tokenData.toJSONString(), 7000L, TimeUnit.SECONDS);
                log.info("获取新的公众号access_token成功: {}", accessToken);
                return accessToken;
            } else {
                throw new RuntimeException("获取公众号AccessToken失败: " + response);
            }
        } catch (Exception e) {
            log.error("获取微信公众号AccessToken失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取微信公众号AccessToken失败: " + e.getMessage());
        }
    }

    /**
     * 通过授权码获取用户 AccessToken（用户授权后使用）
     * 用于 OAuth2 授权流程，获取用户信息
     */
    public JSONObject getOfficialUserAccessToken(String code, Integer tenantId) {
        if (tenantId == null) {
            tenantId = 10048;
        }
        try {
            String appId = getOfficialAppId(tenantId);
            String appSecret = getOfficialAppSecret(tenantId);
            
            String apiUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" 
                + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
            
            String response = HttpUtil.get(apiUrl);
            log.info("获取用户AccessToken响应: {}", response);
            
            JSONObject result = JSON.parseObject(response);
            String accessToken = result.getString("access_token");
            if (StrUtil.isBlank(accessToken)) {
                String errMsg = result.getString("errmsg");
                throw new RuntimeException("获取用户授权失败: " + errMsg);
            }
            return result;
        } catch (Exception e) {
            log.error("获取用户授权AccessToken失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取用户授权失败: " + e.getMessage());
        }
    }

    /**
     * 获取微信公众号用户信息
     */
    public JSONObject getOfficialUserInfo(String accessToken, String openId) {
        try {
            String apiUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
            String response = HttpUtil.get(apiUrl);
            log.info("获取用户信息响应: {}", response);
            return JSON.parseObject(response);
        } catch (Exception e) {
            log.error("获取用户信息失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取用户信息失败: " + e.getMessage());
        }
    }
}
