package com.wzj.soopin.im.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.wzj.soopin.im.service.ITencentIMService;
import com.wzj.soopin.im.util.TLSSigAPIv2;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.Base64;


/**
 * 腾讯IM服务实现类
 *
 * @author wzj
 */
@Slf4j
@Service("systemTencentIMService")
public class TencentIMServiceImpl  implements ITencentIMService {

    @Value("${tencent.im.sdk-app-id}")
    private long sdkAppId;

    @Value("${tencent.im.secret-key}")
    private String secretKey;

    @Value("${tencent.im.administrator}")
    private String adminAccount;

    @Value("${tencent.im.expire-time:180}")
    private int expireTime;

    private final RestTemplate restTemplate = new RestTemplate();

    // 变量替换的正则表达式模式
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$(\\w+)");

    private TLSSigAPIv2 tlsSigApi;

    @PostConstruct
    private void initTlsSigApi() {
        this.tlsSigApi = new TLSSigAPIv2(sdkAppId, secretKey);
    }

    /**
     * 生成用户签名
     *
     * @param userId 用户ID
     * @return 用户签名
     */
    private String generateUserSig(String userId) {
        // 直接调用官方TLSSigAPIv2生成
        return tlsSigApi.genUserSig("administrator", expireTime);
    }

    /**
     * 生成 tls 票据
     *
     * @param sdkappid      应用的 appid
     * @param userId        用户id
     * @param expire        有效期 （时间戳 单位秒）
     * @param priKeyContent 私钥文件内容
     * @return 通过 base64 编码的 tls 票据
     */
    private String genTLSSignature(long sdkappid, String userId, long expire, String priKeyContent) {
        try {
            JSONObject sigDoc = new JSONObject();
            sigDoc.put("TLS.ver", "2.0");
            sigDoc.put("TLS.identifier", userId);
            sigDoc.put("TLS.sdkappid", sdkappid);
            sigDoc.put("TLS.expire", expire);
            sigDoc.put("TLS.time", System.currentTimeMillis() / 1000);

            String base64UserBuf = null;
            if (null != userId) {
                base64UserBuf = base64EncodeUrl(userId.getBytes(StandardCharsets.UTF_8));
                sigDoc.put("TLS.userbuf", base64UserBuf);
            }

            String sig = hmacSHA256(sdkappid, userId, expire, priKeyContent, base64UserBuf);
            if (sig.length() == 0) {
                return "";
            }
            sigDoc.put("TLS.sig", sig);
            Deflater compressor = new Deflater();
            compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
            compressor.finish();
            byte[] compressedBytes = new byte[2048];
            int compressedBytesLength = compressor.deflate(compressedBytes);
            compressor.end();
            return base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength));
        } catch (Exception e) {
            log.error("生成tls票据异常", e);
            return "";
        }
    }

    /**
     * 使用 HMAC-SHA256 生成签名
     */
    private String hmacSHA256(long sdkappid, String userId, long expire, String priKeyContent, String base64UserBuf) {
        try {
            String contentToBeSigned = "TLS.identifier:" + "administrator" + "\n"
                + "TLS.sdkappid:" + sdkappid + "\n"
                + "TLS.time:" + System.currentTimeMillis() / 1000 + "\n"
                + "TLS.expire:" + expire + "\n";
            if (null != base64UserBuf) {
                contentToBeSigned += "TLS.userbuf:" + base64UserBuf + "\n";
            }
            byte[] byteKey = priKeyContent.getBytes(StandardCharsets.UTF_8);
            Mac hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
            hmac.init(keySpec);
            byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes(StandardCharsets.UTF_8));
            return base64EncodeUrl(byteSig);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            return "";
        }
    }

    /**
     * 将字节数组使用 base64 编码（URL 安全）
     */
    private String base64EncodeUrl(byte[] data) {
        byte[] encodedBytes = Base64.getEncoder().encode(data);
        String encodedStr = new String(encodedBytes);
        return encodedStr.replace('+', '*').replace('/', '-').replace('=', '_');
    }

    /**
     * 生成管理员签名
     *
     * @return 管理员签名
     */
    private String generateAdminUserSig() {
        return generateUserSig(adminAccount);
    }

    // 新增结果对象
    public static class TencentIMResult {
        private boolean success;
        private String actionStatus;
        private int errorCode;
        private String errorInfo;
        private String rawResponse;
        // getter/setter
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        public String getActionStatus() { return actionStatus; }
        public void setActionStatus(String actionStatus) { this.actionStatus = actionStatus; }
        public int getErrorCode() { return errorCode; }
        public void setErrorCode(int errorCode) { this.errorCode = errorCode; }
        public String getErrorInfo() { return errorInfo; }
        public void setErrorInfo(String errorInfo) { this.errorInfo = errorInfo; }
        public String getRawResponse() { return rawResponse; }
        public void setRawResponse(String rawResponse) { this.rawResponse = rawResponse; }
    }

    @Override
    public boolean sendMessageToTencentIM(String fromUserId, String toUserId, String msgBody,String cloudCustomData) {
        TencentIMResult result = new TencentIMResult();
        try {
            String userSig = generateAdminUserSig();
            String random = String.valueOf(new Random().nextInt(999999999));
            String url = String.format(
                "https://console.tim.qq.com/v4/openim/sendmsg" +
                    "?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
                sdkAppId,
                adminAccount,
                userSig,
                random);

            JSONArray jsonArray=new JSONArray();
            jsonArray.add(new JSONObject(msgBody));
            JSONObject requestBody = new JSONObject();
            requestBody.put("SyncOtherMachine", 2);
            requestBody.put("From_Account", fromUserId);
            requestBody.put("To_Account", toUserId);
            requestBody.put("MsgRandom", Integer.parseInt(random));
            requestBody.put("MsgBody", jsonArray);
            requestBody.put("CloudCustomData", cloudCustomData);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
            result.setRawResponse(response.getBody());
            log.info("发送消息到腾讯IM结果: {}", response.getBody());
            cn.hutool.json.JSONObject responseJson = new cn.hutool.json.JSONObject(response.getBody());
            result.setActionStatus(responseJson.getStr("ActionStatus"));
            result.setErrorCode(responseJson.getInt("ErrorCode", -1));
            result.setErrorInfo(responseJson.getStr("ErrorInfo"));
            result.setSuccess("OK".equals(result.getActionStatus()) && result.getErrorCode() == 0);
        } catch (Exception e) {
            log.error("发送消息到腾讯IM异常", e);
           return false;
        }
        return true;
    }

    @Override
    public boolean pushToAll(String title, String desc, boolean offlinePush, String ext) {
        try {
            String userSig = generateAdminUserSig();
            String random = String.valueOf(new Random().nextInt(999999999));

            // 构建API请求URL - 使用全员推送接口
            String url = String.format(
                "https://console.tim.qq.com/v4/all_member_push/im_push" +
                    "?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
                sdkAppId,
                adminAccount,
                userSig,
                random);

            // 构建消息内容
            Map<String, Object> msgContent = new HashMap<>();
            msgContent.put("Title", title);
            msgContent.put("Desc", desc);

            // 构建消息体
            Map<String, Object> msgBody = new HashMap<>();
            msgBody.put("MsgType", "TIMCustomElem");
            msgBody.put("MsgContent", msgContent);

            // 如果有扩展字段，添加到消息内容中
            if (ext != null && !ext.isEmpty()) {
                msgContent.put("Ext", ext);
            }

            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("From_Account", adminAccount);
            requestBody.put("MsgRandom", Integer.parseInt(random));
            requestBody.put("MsgBody", new Object[]{msgBody});

            requestBody.put("CloudCustomData", ext);
            // 设置离线推送信息
            if (offlinePush) {
                Map<String, Object> offlinePushInfo = new HashMap<>();
                offlinePushInfo.put("PushFlag", 1); // 1表示推送，0表示不离线推送
                offlinePushInfo.put("Title", title);
                offlinePushInfo.put("Desc", desc);
                offlinePushInfo.put("Ext", ext);
                requestBody.put("OfflinePushInfo", offlinePushInfo);
            }

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            // 发送请求
            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

            log.info("全员推送消息结果: {}", response.getBody());

            // 解析响应判断是否成功
            JSONObject responseJson = new JSONObject(response);
            return "OK".equals(responseJson.getStr("ActionStatus"));
        } catch (Exception e) {
            log.error("全员推送消息异常", e);
            return false;
        }
    }

    @Override
    public boolean pushByAttributes(String title, String desc, Map<String, Object> attributes, boolean offlinePush, String ext) {
        try {
            String userSig = generateAdminUserSig();
            String random = String.valueOf(new Random().nextInt(999999999));

            // 构建API请求URL - 使用属性推送接口
            String url = String.format(
                "https://console.tim.qq.com/v4/all_member_push/im_push_attr" +
                    "?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
                sdkAppId,
                adminAccount,
                userSig,
                random);

            // 构建消息内容
            Map<String, Object> msgContent = new HashMap<>();
            msgContent.put("Title", title);
            msgContent.put("Desc", desc);

            // 构建消息体
            Map<String, Object> msgBody = new HashMap<>();
            msgBody.put("MsgType", "TIMCustomElem");
            msgBody.put("MsgContent", msgContent);

            // 如果有扩展字段，添加到消息内容中
            if (ext != null && !ext.isEmpty()) {
                msgContent.put("Ext", ext);
            }

            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("From_Account", adminAccount);
            requestBody.put("MsgRandom", Integer.parseInt(random));
            requestBody.put("MsgBody", new Object[]{msgBody});
            requestBody.put("AttrNames", attributes.keySet().toArray(new String[0]));
            requestBody.put("AttrValues", attributes.values().toArray());

            // 设置离线推送信息
            if (offlinePush) {
                Map<String, Object> offlinePushInfo = new HashMap<>();
                offlinePushInfo.put("PushFlag", 1); // 1表示推送，0表示不离线推送
                offlinePushInfo.put("Title", title);
                offlinePushInfo.put("Desc", desc);
                offlinePushInfo.put("Ext", ext);
                requestBody.put("OfflinePushInfo", offlinePushInfo);
            }

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            // 发送请求
            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

            log.info("属性推送消息结果: {}", response.getBody());

            // 解析响应判断是否成功
            JSONObject responseJson = new JSONObject(response.getBody());
            return "OK".equals(responseJson.getStr("ActionStatus"));
        } catch (Exception e) {
            log.error("属性推送消息异常", e);
            return false;
        }
    }

    @Override
    public boolean pushByTags(String title, String desc, List<String> tags, boolean offlinePush, String ext) {
        try {
            String userSig = generateAdminUserSig();
            String random = String.valueOf(new Random().nextInt(999999999));

            // 构建API请求URL - 使用标签推送接口
            String url = String.format(
                "https://console.tim.qq.com/v4/all_member_push/im_push_tags" +
                    "?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
                sdkAppId,
                adminAccount,
                userSig,
                random);

            // 构建消息内容
            Map<String, Object> msgContent = new HashMap<>();
            msgContent.put("Title", title);
            msgContent.put("Desc", desc);

            // 构建消息体
            Map<String, Object> msgBody = new HashMap<>();
            msgBody.put("MsgType", "TIMCustomElem");
            msgBody.put("MsgContent", msgContent);

            // 如果有扩展字段，添加到消息内容中
            if (ext != null && !ext.isEmpty()) {
                msgContent.put("Ext", ext);
            }

            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("From_Account", adminAccount);
            requestBody.put("MsgRandom", Integer.parseInt(random));
            requestBody.put("MsgBody", new Object[]{msgBody});
            requestBody.put("TagList", tags);

            // 设置离线推送信息
            if (offlinePush) {
                Map<String, Object> offlinePushInfo = new HashMap<>();
                offlinePushInfo.put("PushFlag", 1); // 1表示推送，0表示不离线推送
                offlinePushInfo.put("Title", title);
                offlinePushInfo.put("Desc", desc);
                offlinePushInfo.put("Ext", ext);
                requestBody.put("OfflinePushInfo", offlinePushInfo);
            }

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            // 发送请求
            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

            log.info("标签推送消息结果: {}", response.getBody());

            // 解析响应判断是否成功
            JSONObject responseJson = new JSONObject(response.getBody());
            return "OK".equals(responseJson.getStr("ActionStatus"));
        } catch (Exception e) {
            log.error("标签推送消息异常", e);
            return false;
        }
    }

    @Override
    public boolean pushToUsers(String title, String desc, List<String> userIds, boolean offlinePush, String ext) {
        try {
            String userSig = generateAdminUserSig();
            String random = String.valueOf(new Random().nextInt(999999999));

            // 构建API请求URL - 使用批量单发接口
            String url = String.format(
                "https://console.tim.qq.com/v4/openim/batchsendmsg" +
                    "?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
                sdkAppId,
                adminAccount,
                userSig,
                random);

            // 构建消息内容
            Map<String, Object> msgContent = new HashMap<>();
            msgContent.put("Title", title);
            msgContent.put("Desc", desc);

            // 构建消息体
            Map<String, Object> msgBody = new HashMap<>();
            msgBody.put("MsgType", "TIMCustomElem");
            msgBody.put("MsgContent", msgContent);

            // 如果有扩展字段，添加到消息内容中
            if (ext != null && !ext.isEmpty()) {
                msgContent.put("Ext", ext);
            }

            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("From_Account", adminAccount);
            requestBody.put("To_Account", userIds);
            requestBody.put("MsgRandom", Integer.parseInt(random));
            requestBody.put("MsgBody", new Object[]{msgBody});

            // 设置离线推送信息
            if (offlinePush) {
                Map<String, Object> offlinePushInfo = new HashMap<>();
                offlinePushInfo.put("PushFlag", 1); // 1表示推送，0表示不离线推送
                offlinePushInfo.put("Title", title);
                offlinePushInfo.put("Desc", desc);
                offlinePushInfo.put("Ext", ext);
                requestBody.put("OfflinePushInfo", offlinePushInfo);
            }

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            // 发送请求
            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

            log.info("指定用户推送消息结果: {}", response.getBody());

            // 解析响应判断是否成功
            JSONObject responseJson = new JSONObject(response.getBody());
            return "OK".equals(responseJson.getStr("ActionStatus"));
        } catch (Exception e) {
            log.error("指定用户推送消息异常", e);
            return false;
        }
    }

    @Override
    public String processMessageVariables(String content, Map<String, String> variables) {
        if (content == null || variables == null || variables.isEmpty()) {
            return content;
        }

        Matcher matcher = VARIABLE_PATTERN.matcher(content);
        StringBuffer sb = new StringBuffer();

        while (matcher.find()) {
            String variableName = matcher.group(1);
            String replacement = variables.getOrDefault(variableName, "$" + variableName);
            matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
        }

        matcher.appendTail(sb);
        return sb.toString();
    }
}
