package org.hzhub.workflow.wecom;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hzhub.common.redis.utils.RedisUtils;
import org.hzhub.workflow.service.IWecomTenantConfigService;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 企业微信 API 客户端
 * <p>封装企业微信 OA 审批接口的 HTTP 调用，根据当前租户动态读取 corpid/corpsecret</p>
 *
 * @author hzhub
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WecomApiClient {

    private static final String TOKEN_CACHE_KEY_PREFIX = "wecom_access_token:";

    private final IWecomTenantConfigService tenantConfigService;
    private final WecomConfig wecomConfig;

    /**
     * 获取当前租户的 access_token（带 Redis 缓存）
     */
    public String getAccessToken() {
        String corpid = tenantConfigService.getCorpId();
        String corpsecret = tenantConfigService.getCorpSecret();
        String tokenKey = TOKEN_CACHE_KEY_PREFIX + corpid;

        String cached = RedisUtils.getCacheObject(tokenKey);
        if (cached != null) {
            return cached;
        }
        return refreshToken(corpid, corpsecret, tokenKey);
    }

    private String refreshToken(String corpid, String corpsecret, String tokenKey) {
        String url = wecomConfig.getApiBaseUrl() + "/cgi-bin/gettoken";
        Map<String, Object> params = new HashMap<>();
        params.put("corpid", corpid);
        params.put("corpsecret", corpsecret);

        String resp = HttpUtil.get(url, params);
        log.debug("获取 access_token 响应: {}", resp);

        var json = JSONUtil.parseObj(resp);
        int errcode = json.getInt("errcode", -1);
        if (errcode == 0) {
            String token = json.getStr("access_token");
            int expiresIn = json.getInt("expires_in", 7200);
            // 提前 300 秒过期
            RedisUtils.setCacheObject(tokenKey, token, Duration.ofSeconds(expiresIn - 300));
            return token;
        }
        log.error("获取 access_token 失败: {}", resp);
        throw new RuntimeException("获取企业微信 access_token 失败: " + json.getStr("errmsg"));
    }

    /**
     * 获取审批模板详情
     */
    public String getTemplateDetail(String templateId) {
        String url = wecomConfig.getApiBaseUrl() + "/cgi-bin/oa/gettemplatedetail?access_token=" + getAccessToken();
        Map<String, Object> body = new HashMap<>();
        body.put("template_id", templateId);
        String resp = HttpUtil.post(url, JSONUtil.toJsonStr(body));
        log.debug("获取模板详情({}) 响应: {}", templateId, resp);
        return resp;
    }

    /**
     * 批量获取审批单号
     * <p>规则：limit 最大100；endtime - starttime 不超过31天；调用频率不超过600次/分</p>
     */
    public String getApprovalInfo(long starttime, long endtime, String cursor, int limit, List<Map<String, Object>> filters) {
        // 规则2: 时间跨度不能超过31天
        long maxSpan = 31L * 24 * 3600; // 31天秒数
        if (endtime <= starttime) {
            throw new IllegalArgumentException("endtime 必须大于 starttime");
        }
        if (endtime - starttime > maxSpan) {
            throw new IllegalArgumentException("起始时间跨度不能超过31天");
        }

        // 规则3: 调用频率限制 600次/分，即最小间隔100ms
        String rateKey = "wecom:rate:approval_info";
        Long currentCount = RedisUtils.incrAtomicValue(rateKey);
        if (currentCount != null && currentCount == 1) {
            RedisUtils.expire(rateKey, Duration.ofMinutes(1));
        }
        if (currentCount != null && currentCount > 600) {
            throw new RuntimeException("企业微信审批接口调用频率超限(600次/分)，请稍后重试");
        }

        String url = wecomConfig.getApiBaseUrl() + "/cgi-bin/oa/getapprovalinfo?access_token=" + getAccessToken();
        Map<String, Object> body = new HashMap<>();
        body.put("starttime", starttime);
        body.put("endtime", endtime);
        body.put("cursor", cursor != null ? cursor : "0");
        // 规则1: 一次最多拉取100条
        body.put("limit", Math.min(limit, 100));
        if (filters != null && !filters.isEmpty()) {
            body.put("filters", filters);
        }
        String resp = HttpUtil.post(url, JSONUtil.toJsonStr(body));
        log.info("批量获取审批单号 响应: {}", resp);
        return resp;
    }

    /**
     * 获取审批详情
     */
    public String getApprovalDetail(String spNo) {
        String url = wecomConfig.getApiBaseUrl() + "/cgi-bin/oa/getapprovaldetail?access_token=" + getAccessToken();
        Map<String, Object> body = new HashMap<>();
        body.put("sp_no", spNo);
        String resp = HttpUtil.post(url, JSONUtil.toJsonStr(body));
        log.info("获取审批详情({}) 完整响应: {}", spNo, resp);
        return resp;
    }

    /**
     * 提交审批申请
     */
    public String submitApproval(String body) {
        String url = wecomConfig.getApiBaseUrl() + "/cgi-bin/oa/applyevent?access_token=" + getAccessToken();
        String resp = HttpUtil.post(url, body);
        log.debug("提交审批申请 响应: {}", resp);
        return resp;
    }

    /**
     * 获取部门列表
     *
     * @param id 部门ID，0表示获取所有部门
     * @return WeCom 原始响应 JSON
     */
    public String listDepartments(Integer id) {
        String url = wecomConfig.getApiBaseUrl() + "/cgi-bin/department/list?access_token=" + getAccessToken() + "&id=" + (id != null ? id : 0);
        String resp = HttpUtil.get(url);
        log.debug("获取部门列表({}) 响应: {}", id, resp);
        return resp;
    }

    /**
     * 获取部门成员详情列表
     *
     * @param departmentId 部门ID
     * @param fetchChild   是否获取子部门数据（1是 0否）
     * @return WeCom 原始响应 JSON
     */
    public String listUsers(Integer departmentId, Integer fetchChild) {
        String url = wecomConfig.getApiBaseUrl() + "/cgi-bin/user/list?access_token=" + getAccessToken()
            + "&department_id=" + (departmentId != null ? departmentId : 1)
            + "&fetch_child=" + (fetchChild != null ? fetchChild : 1);
        String resp = HttpUtil.get(url);
        log.debug("获取部门成员详情({}) 响应: {}", departmentId, resp);
        return resp;
    }
}
