package com.haha.miniapp.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.crypto.digest.DigestUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;

/**
 * 微信客服消息回调
 *
 * 在微信公众平台 -> 功能 -> 客服 -> 客服消息回调配置中设置 URL 后，
 * 用户向客服发送消息时，微信服务器会将消息推送到此接口。
 *
 * 配置项：
 * - URL: {baseUrl}/callback/wechat/customer-service
 * - Token: 与 wechat.miniapp.customer-service-token 一致
 *
 * 使用步骤：
 * 1. 在微信公众平台开通「客服」功能
 * 2. 添加客服人员
 * 3. （可选）配置消息回调，用于接收用户消息实现自动回复
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/callback/wechat/customer-service")
@SaIgnore
public class WeChatCustomerController {

    @Value("${wechat.miniapp.customer-service-token}")
    private String token;

    /**
     * 验证消息的确来自微信服务器
     *
     * 微信服务器会发送 GET 请求到配置的 URL 进行验证，
     * 需要将 signature 与本地计算的结果比对，匹配则原样返回 echostr。
     */
    @GetMapping
    public String verify(HttpServletRequest request) {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");

        log.info("[微信客服] 收到验证请求 - signature: {}, timestamp: {}, nonce: {}, echostr: {}",
                signature, timestamp, nonce, echostr);

        if (checkSignature(signature, timestamp, nonce)) {
            log.info("[微信客服] 验证成功，返回 echostr: {}", echostr);
            return echostr;
        }

        log.warn("[微信客服] 验证失败 - signature: {}, timestamp: {}, nonce: {}", signature, timestamp, nonce);
        return "invalid";
    }

    /**
     * 接收用户发送的客服消息
     *
     * 用户在客服会话中发送消息后，微信服务器会推送 XML 格式的消息到此接口。
     * 消息类型包括：text, image, voice, video, miniprogrampage 等。
     *
     * 如果需要自动回复，返回 XML 格式的响应消息。
     * 不需要自动回复时，返回空字符串或 "success"。
     */
    @PostMapping(produces = "application/xml;charset=UTF-8")
    public String handleMessage(HttpServletRequest request) {
        try {
            String signature = request.getParameter("signature");
            String timestamp = request.getParameter("timestamp");
            String nonce = request.getParameter("nonce");

            if (!checkSignature(signature, timestamp, nonce)) {
                log.warn("[微信客服] 消息签名验证失败");
                return "invalid";
            }

            byte[] bytes = request.getInputStream().readAllBytes();
            String xml = new String(bytes, StandardCharsets.UTF_8);
            log.info("[微信客服] 收到消息: {}", xml);

            Map<String, Object> msgMap = XmlUtil.xmlToMap(xml);
            String msgType = (String) msgMap.get("MsgType");
            String fromUser = (String) msgMap.get("FromUserName");
            String content = (String) msgMap.get("Content");

            log.info("[微信客服] 用户 {} 发送了 {} 类型消息: {}", fromUser, msgType, content);

            return handleAutoReply(msgMap);
        } catch (Exception e) {
            log.error("[微信客服] 处理消息异常", e);
            return "success";
        }
    }

    /**
     * 校验签名
     *
     * 将 token、timestamp、nonce 按字典序排序后拼接成字符串，进行 SHA1 加密，
     * 结果与 signature 比对。
     */
    private boolean checkSignature(String signature, String timestamp, String nonce) {
        if (signature == null || timestamp == null || nonce == null) {
            return false;
        }
        String[] arr = {token, timestamp, nonce};
        Arrays.sort(arr);
        StringBuilder sb = new StringBuilder();
        for (String s : arr) {
            sb.append(s);
        }
        String calculated = DigestUtil.sha1Hex(sb.toString());
        return calculated.equals(signature);
    }

    /**
     * 处理自动回复
     *
     * 根据消息类型和内容，返回对应的自动回复 XML。
     * 不需要自动回复时返回空字符串，微信不会回复任何消息。
     */
    private String handleAutoReply(Map<String, Object> msgMap) {
        String msgType = (String) msgMap.get("MsgType");
        String fromUser = (String) msgMap.get("FromUserName");
        String toUser = (String) msgMap.get("ToUserName");

        if ("text".equals(msgType)) {
            String content = (String) msgMap.get("Content");
            String reply = buildTextReply(content);
            if (reply != null) {
                return buildReplyXml(fromUser, toUser, reply);
            }
        }

        return "success";
    }

    /**
     * 根据用户消息内容构建自动回复文本
     */
    private String buildTextReply(String content) {
        if (content == null) return null;

        if (content.contains("人工") || content.contains("转人工")) {
            return "正在为您转接人工客服，请稍候...";
        }
        if (content.contains("退款") || content.contains("退钱")) {
            return "如需申请退款，请前往「我的订单」-「订单详情」-「申请退款」操作，或拨打客服热线 400-0755-315。";
        }
        if (content.contains("开门") || content.contains("门没开") || content.contains("打不开")) {
            return "门打不开？请尝试以下方法：\n1. 检查手机蓝牙是否开启\n2. 重新扫码尝试\n3. 联系设备维护人员\n如仍无法解决，请拨打客服热线 400-0755-315。";
        }
        if (content.contains("扣款") || content.contains("多扣") || content.contains("扣错")) {
            return "如对扣款有疑问，请前往「我的订单」查看订单详情，如有错误可申请退款。如有其他疑问，请拨打客服热线 400-0755-315。";
        }
        if (content.contains("客服") || content.contains("电话")) {
            return "我们的客服热线：400-0755-315（工作日 9:00-18:00）。";
        }
        if (content.contains("你好") || content.contains("您好") || content.contains("hi") || content.contains("hello")) {
            return "您好！欢迎使用 AI 零售柜。请问有什么可以帮您？\n\n常见问题：\n• 如何退款：前往「我的订单」申请\n• 门打不开：重新扫码或联系维护人员\n• 扣款疑问：查看订单详情或申请退款\n\n如需人工帮助，请回复「转人工」。";
        }

        return null;
    }

    /**
     * 构建回复 XML
     */
    private String buildReplyXml(String fromUser, String toUser, String content) {
        return String.format(
                "<xml>" +
                "<ToUserName><![CDATA[%s]]></ToUserName>" +
                "<FromUserName><![CDATA[%s]]></FromUserName>" +
                "<CreateTime>%d</CreateTime>" +
                "<MsgType><![CDATA[text]]></MsgType>" +
                "<Content><![CDATA[%s]]></Content>" +
                "</xml>",
                fromUser, toUser, System.currentTimeMillis() / 1000, content
        );
    }
}
