package com.ruoyi.jarvis.wecom;

import com.alibaba.fastjson2.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 调用 wxSend 的企微应用文本主动推送（POST /wecom/active-push）。
 */
@Component
public class WxSendWeComPushClient {

    private static final Logger log = LoggerFactory.getLogger(WxSendWeComPushClient.class);

    public static final String HEADER_PUSH_SECRET = "X-WxSend-WeCom-Push-Secret";

    @Value("${jarvis.wecom.wxsend-base-url:}")
    private String wxsendBaseUrl;

    @Value("${jarvis.wecom.push-secret:}")
    private String pushSecret;

    /**
     * 与 {@link #scheduleActivePushes(String, String, List)} 相同顺序与延迟，但在当前线程同步执行，并返回是否全部成功。
     * {@code wecomCallbackAgentId} 与回调 XML 中 AgentId 一致时须传入，便于 wxSend 选用对应应用 secret 调用 message/send。
     */
    public boolean pushAfterPassiveDelaySync(String toUser, String wecomCallbackAgentId, List<String> contents) {
        final String userId = toUser != null ? toUser.trim() : "";
        final List<String> list = contents != null ? new ArrayList<>(contents) : Collections.emptyList();
        final String agentOpt = StringUtils.hasText(wecomCallbackAgentId) ? wecomCallbackAgentId.trim() : null;

        if (!StringUtils.hasText(wxsendBaseUrl)) {
            log.error("企微主动推送未执行：未配置 jarvis.wecom.wxsend-base-url（用户会话中收不到查询结果或报错）");
            return false;
        }
        if (!StringUtils.hasText(pushSecret)) {
            log.error("企微主动推送未执行：未配置 jarvis.wecom.push-secret");
            return false;
        }
        if (!StringUtils.hasText(userId)) {
            log.error("企微主动推送未执行：目标成员 UserID 为空");
            return false;
        }
        if (list.isEmpty()) {
            log.warn("企微主动推送未执行：推送内容为空 userId={}", userId);
            return false;
        }

        try {
            Thread.sleep(450);
            String base = normalizeBase(wxsendBaseUrl);
            String url = base + "/wecom/active-push";
            boolean anySent = false;
            boolean allOk = true;
            for (String c : list) {
                if (!StringUtils.hasText(c)) {
                    continue;
                }
                anySent = true;
                if (!postJson(url, userId, c.trim(), agentOpt)) {
                    allOk = false;
                }
                Thread.sleep(120);
            }
            if (!anySent) {
                log.error("企微主动推送：无有效正文段 userId={}", userId);
                return false;
            }
            if (!allOk) {
                log.error("企微主动推送部分失败 userId={}（请检查 wxSend /wecom/active-push 与密钥）", userId);
            }
            return allOk;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("企微主动推送被中断 userId={}", userId, e);
            return false;
        } catch (Exception e) {
            log.error("企微主动推送异常 userId={}", userId, e);
            return false;
        }
    }

    /**
     * 在被动回复返回后再发，保证企微侧先出现首条被动消息。
     * 无分段（如「开/慢开」仅异步 TG、被动已单独回执）时不调度，避免空列表告警。
     */
    public void scheduleActivePushes(String toUser, String wecomCallbackAgentId, List<String> contents) {
        final String agentPass = wecomCallbackAgentId != null ? wecomCallbackAgentId.trim() : "";
        final List<String> list = contents != null ? new ArrayList<>(contents) : Collections.emptyList();
        if (list.isEmpty()) {
            return;
        }
        final String userId = toUser != null ? toUser.trim() : "";
        CompletableFuture.runAsync(() -> {
            boolean ok = pushAfterPassiveDelaySync(
                userId, StringUtils.hasText(agentPass) ? agentPass : null, list);
            if (!ok) {
                log.error(
                    "scheduleActivePushes 未完全成功 userId={}（用户可能未收到会话内的后续分段）",
                    userId);
            }
        });
    }

    private static String normalizeBase(String base) {
        String b = base.trim();
        if (b.endsWith("/")) {
            return b.substring(0, b.length() - 1);
        }
        return b;
    }

    /** @return HTTP 2xx 且无异常时为 true */
    private boolean postJson(String url, String toUser, String content, String agentIdOpt) {
        JSONObject body = new JSONObject();
        body.put("toUser", toUser);
        body.put("content", content);
        if (StringUtils.hasText(agentIdOpt)) {
            body.put("agentId", agentIdOpt.trim());
        }
        byte[] bytes = body.toJSONString().getBytes(StandardCharsets.UTF_8);
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(60000);
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            conn.setRequestProperty(HEADER_PUSH_SECRET, pushSecret);
            try (OutputStream os = conn.getOutputStream()) {
                os.write(bytes);
            }
            int code = conn.getResponseCode();
            InputStream is = code >= 200 && code < 300 ? conn.getInputStream() : conn.getErrorStream();
            String resp = readAll(is);
            if (code < 200 || code >= 300) {
                log.error("wxSend active-push HTTP {} url={} body={}", code, url, resp);
                return false;
            }
            if (StringUtils.hasText(resp)) {
                try {
                    JSONObject jo = JSONObject.parseObject(resp);
                    if (jo != null && jo.containsKey("code")) {
                        Integer biz = jo.getInteger("code");
                        if (biz != null && biz != 200) {
                            log.error(
                                "wxSend active-push 业务失败 http={} code={} msg={} body={}",
                                code, biz, jo.getString("msg"), resp);
                            return false;
                        }
                    }
                } catch (Exception parseSkip) {
                    // 非 JSON 则仅以 HTTP 为准
                }
            }
            log.debug("wxSend active-push OK http={} resp={}", code, resp);
            return true;
        } catch (Exception e) {
            log.error("wxSend active-push 请求失败 url={} err={}", url, e.toString(), e);
            return false;
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }

    private static String readAll(InputStream is) throws java.io.IOException {
        if (is == null) {
            return "";
        }
        byte[] buf = new byte[4096];
        StringBuilder sb = new StringBuilder();
        int n;
        while ((n = is.read(buf)) >= 0) {
            sb.append(new String(buf, 0, n, StandardCharsets.UTF_8));
        }
        return sb.toString();
    }
}
