package org.dromara.mp.utils;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * 微信公众号工具类
 *
 * @author pengles
 */
public class WxMpUtils {

    private static final Logger logger = LoggerFactory.getLogger(WxMpUtils.class);

    /**
     * 手机号正则表达式
     */
    private static final Pattern MOBILE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");

    /**
     * 邮箱正则表达式
     */
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");

    /**
     * 身份证号正则表达式
     */
    private static final Pattern ID_CARD_PATTERN = Pattern.compile("^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");

    /**
     * 验证微信签名
     *
     * @param token     微信公众号token
     * @param signature 微信签名
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @return 验证结果
     */
    public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {
        String[] arr = new String[]{token, timestamp, nonce};
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (String s : arr) {
            content.append(s);
        }

        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(content.toString().getBytes());
            StringBuilder hexStr = new StringBuilder();
            for (byte b : digest) {
                String shaHex = Integer.toHexString(b & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            return hexStr.toString().equals(signature);
        } catch (NoSuchAlgorithmException e) {
            logger.error("SHA-1算法不存在", e);
            return false;
        }
    }

    /**
     * 构建文本回复消息
     *
     * @param content   回复内容
     * @param wxMessage 接收到的消息
     * @return 回复消息
     */
    public static WxMpXmlOutMessage buildTextMessage(String content, WxMpXmlMessage wxMessage) {
        return WxMpXmlOutMessage.TEXT()
                .content(content)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
    }

    /**
     * 构建图片回复消息
     *
     * @param mediaId   图片媒体ID
     * @param wxMessage 接收到的消息
     * @return 回复消息
     */
    public static WxMpXmlOutMessage buildImageMessage(String mediaId, WxMpXmlMessage wxMessage) {
        return WxMpXmlOutMessage.IMAGE()
                .mediaId(mediaId)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
    }

    /**
     * 构建语音回复消息
     *
     * @param mediaId   语音媒体ID
     * @param wxMessage 接收到的消息
     * @return 回复消息
     */
    public static WxMpXmlOutMessage buildVoiceMessage(String mediaId, WxMpXmlMessage wxMessage) {
        return WxMpXmlOutMessage.VOICE()
                .mediaId(mediaId)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
    }

    /**
     * 构建视频回复消息
     *
     * @param mediaId     视频媒体ID
     * @param title       视频标题
     * @param description 视频描述
     * @param wxMessage   接收到的消息
     * @return 回复消息
     */
    public static WxMpXmlOutMessage buildVideoMessage(String mediaId, String title, String description, WxMpXmlMessage wxMessage) {
        return WxMpXmlOutMessage.VIDEO()
                .mediaId(mediaId)
                .title(title)
                .description(description)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
    }

    /**
     * 构建音乐回复消息
     *
     * @param title        音乐标题
     * @param description  音乐描述
     * @param musicUrl     音乐链接
     * @param hqMusicUrl   高质量音乐链接
     * @param thumbMediaId 缩略图媒体ID
     * @param wxMessage    接收到的消息
     * @return 回复消息
     */
    public static WxMpXmlOutMessage buildMusicMessage(String title, String description, String musicUrl,
                                                      String hqMusicUrl, String thumbMediaId, WxMpXmlMessage wxMessage) {
        return WxMpXmlOutMessage.MUSIC()
                .title(title)
                .description(description)
                .musicUrl(musicUrl)
                .hqMusicUrl(hqMusicUrl)
                .thumbMediaId(thumbMediaId)
                .fromUser(wxMessage.getToUser())
                .toUser(wxMessage.getFromUser())
                .build();
    }

    /**
     * 判断是否为文本消息
     *
     * @param wxMessage 微信消息
     * @return 是否为文本消息
     */
    public static boolean isTextMessage(WxMpXmlMessage wxMessage) {
        return WxConsts.XmlMsgType.TEXT.equals(wxMessage.getMsgType());
    }

    /**
     * 判断是否为图片消息
     *
     * @param wxMessage 微信消息
     * @return 是否为图片消息
     */
    public static boolean isImageMessage(WxMpXmlMessage wxMessage) {
        return WxConsts.XmlMsgType.IMAGE.equals(wxMessage.getMsgType());
    }

    /**
     * 判断是否为语音消息
     *
     * @param wxMessage 微信消息
     * @return 是否为语音消息
     */
    public static boolean isVoiceMessage(WxMpXmlMessage wxMessage) {
        return WxConsts.XmlMsgType.VOICE.equals(wxMessage.getMsgType());
    }

    /**
     * 判断是否为视频消息
     *
     * @param wxMessage 微信消息
     * @return 是否为视频消息
     */
    public static boolean isVideoMessage(WxMpXmlMessage wxMessage) {
        return WxConsts.XmlMsgType.VIDEO.equals(wxMessage.getMsgType()) ||
                WxConsts.XmlMsgType.SHORTVIDEO.equals(wxMessage.getMsgType());
    }

    /**
     * 判断是否为地理位置消息
     *
     * @param wxMessage 微信消息
     * @return 是否为地理位置消息
     */
    public static boolean isLocationMessage(WxMpXmlMessage wxMessage) {
        return WxConsts.XmlMsgType.LOCATION.equals(wxMessage.getMsgType());
    }

    /**
     * 判断是否为链接消息
     *
     * @param wxMessage 微信消息
     * @return 是否为链接消息
     */
    public static boolean isLinkMessage(WxMpXmlMessage wxMessage) {
        return WxConsts.XmlMsgType.LINK.equals(wxMessage.getMsgType());
    }

    /**
     * 判断是否为事件消息
     *
     * @param wxMessage 微信消息
     * @return 是否为事件消息
     */
    public static boolean isEventMessage(WxMpXmlMessage wxMessage) {
        return WxConsts.XmlMsgType.EVENT.equals(wxMessage.getMsgType());
    }

    /**
     * 判断是否为关注事件
     *
     * @param wxMessage 微信消息
     * @return 是否为关注事件
     */
    public static boolean isSubscribeEvent(WxMpXmlMessage wxMessage) {
        return isEventMessage(wxMessage) && WxConsts.EventType.SUBSCRIBE.equals(wxMessage.getEvent());
    }

    /**
     * 判断是否为取消关注事件
     *
     * @param wxMessage 微信消息
     * @return 是否为取消关注事件
     */
    public static boolean isUnsubscribeEvent(WxMpXmlMessage wxMessage) {
        return isEventMessage(wxMessage) && WxConsts.EventType.UNSUBSCRIBE.equals(wxMessage.getEvent());
    }

    /**
     * 判断是否为菜单点击事件
     *
     * @param wxMessage 微信消息
     * @return 是否为菜单点击事件
     */
    public static boolean isMenuClickEvent(WxMpXmlMessage wxMessage) {
        return isEventMessage(wxMessage) && WxConsts.EventType.CLICK.equals(wxMessage.getEvent());
    }

    /**
     * 判断是否为扫码事件
     *
     * @param wxMessage 微信消息
     * @return 是否为扫码事件
     */
    public static boolean isScanEvent(WxMpXmlMessage wxMessage) {
        return isEventMessage(wxMessage) &&
                (WxConsts.EventType.SCAN.equals(wxMessage.getEvent()) ||
                        (WxConsts.EventType.SUBSCRIBE.equals(wxMessage.getEvent()) && wxMessage.getEventKey() != null && wxMessage.getEventKey().startsWith("qrscene_")));
    }

    /**
     * 验证手机号格式
     *
     * @param mobile 手机号
     * @return 是否有效
     */
    public static boolean isValidMobile(String mobile) {
        return mobile != null && MOBILE_PATTERN.matcher(mobile).matches();
    }

    /**
     * 验证邮箱格式
     *
     * @param email 邮箱
     * @return 是否有效
     */
    public static boolean isValidEmail(String email) {
        return email != null && EMAIL_PATTERN.matcher(email).matches();
    }

    /**
     * 验证身份证号格式
     *
     * @param idCard 身份证号
     * @return 是否有效
     */
    public static boolean isValidIdCard(String idCard) {
        return idCard != null && ID_CARD_PATTERN.matcher(idCard).matches();
    }

    /**
     * 获取扫码事件的场景值
     *
     * @param wxMessage 微信消息
     * @return 场景值
     */
    public static String getScanSceneValue(WxMpXmlMessage wxMessage) {
        if (!isScanEvent(wxMessage)) {
            return null;
        }

        String eventKey = wxMessage.getEventKey();
        if (eventKey == null) {
            return null;
        }

        // 如果是关注时扫码，eventKey格式为qrscene_场景值
        if (eventKey.startsWith("qrscene_")) {
            return eventKey.substring(8);
        }

        // 如果是已关注用户扫码，eventKey就是场景值
        return eventKey;
    }

    /**
     * 过滤敏感词
     *
     * @param content 原始内容
     * @return 过滤后的内容
     */
    public static String filterSensitiveWords(String content) {
        if (content == null || content.trim().isEmpty()) {
            return content;
        }

        // 这里可以接入敏感词过滤服务
        // 简单示例：替换一些常见敏感词
        String filtered = content;
        String[] sensitiveWords = {"fuck", "shit", "damn"};

        for (String word : sensitiveWords) {
            filtered = filtered.replaceAll("(?i)" + word, "***");
        }

        return filtered;
    }

    /**
     * 截取字符串，超出长度用省略号表示
     *
     * @param str       原始字符串
     * @param maxLength 最大长度
     * @return 截取后的字符串
     */
    public static String truncateString(String str, int maxLength) {
        if (str == null || str.length() <= maxLength) {
            return str;
        }
        return str.substring(0, maxLength - 3) + "...";
    }
}