"""
加密工具模块

实现微信加密相关的工具函数
"""

import hashlib
import base64
import time
import random
from typing import Dict
import xml.etree.ElementTree as ET


class Crypto:
    """
    加密工具类

    用于处理微信消息加密、签名验证等操作
    """

    @staticmethod
    def generate_signature(token: str, timestamp: str, nonce: str) -> str:
        """
        生成微信签名

        :param token: 微信公众号token
        :param timestamp: 时间戳
        :param nonce: 随机数
        :return: 签名
        """
        # 对token、timestamp、nonce按字典序排序
        params = [token, timestamp, nonce]
        params.sort()
        # 拼接成字符串
        params_str = "".join(params)
        # 计算SHA1哈希
        sha1 = hashlib.sha1()
        sha1.update(params_str.encode("utf-8"))
        return sha1.hexdigest()

    @staticmethod
    def verify_signature(
        token: str, signature: str, timestamp: str, nonce: str
    ) -> bool:
        """
        验证微信签名

        :param token: 微信公众号token
        :param signature: 微信传递的签名
        :param timestamp: 时间戳
        :param nonce: 随机数
        :return: 签名是否有效
        """
        # 生成签名
        generated_signature = Crypto.generate_signature(token, timestamp, nonce)
        # 比较签名
        return generated_signature == signature

    @staticmethod
    def decrypt_message(encrypted_msg: str, encoding_aes_key: str, app_id: str) -> str:
        """
        解密微信消息

        :param encrypted_msg: 加密的消息
        :param encoding_aes_key: 消息加密密钥
        :param app_id: 微信公众号AppID
        :return: 解密后的消息
        """
        # Base64解码encrypted_msg
        encrypted_data = base64.b64decode(encrypted_msg)

        # 提取随机数
        # 提取消息长度
        msg_len = int.from_bytes(encrypted_data[16:20], byteorder="big")
        # 提取消息内容
        msg = encrypted_data[20 : 20 + msg_len].decode("utf-8")
        # 提取AppID
        from_app_id = encrypted_data[20 + msg_len :].decode("utf-8")

        # 验证AppID
        if from_app_id != app_id:
            raise ValueError("❌ AppID验证失败")

        return msg

    @staticmethod
    def encrypt_message(msg: str, encoding_aes_key: str, app_id: str) -> str:
        """
        加密微信消息

        :param msg: 待加密的消息
        :param encoding_aes_key: 消息加密密钥
        :param app_id: 微信公众号AppID
        :return: 加密后的消息
        """
        # 生成16位随机数
        rand_msg = "".join([chr(random.randint(0, 255)) for _ in range(16)]).encode(
            "utf-8"
        )
        # 消息长度
        msg_len = len(msg.encode("utf-8"))
        msg_len_bytes = msg_len.to_bytes(4, byteorder="big")
        # 消息内容
        msg_bytes = msg.encode("utf-8")
        # AppID
        app_id_bytes = app_id.encode("utf-8")

        # 拼接数据
        full_msg = rand_msg + msg_len_bytes + msg_bytes + app_id_bytes

        # 计算填充长度
        pad_len = 32 - (len(full_msg) % 32)
        # 填充
        full_msg += bytes([pad_len]) * pad_len

        # 加密（这里简化处理，实际需要使用AES-CBC加密）
        # 注意：完整的实现需要使用pycryptodome等库

        # Base64编码
        encrypted_msg = base64.b64encode(full_msg).decode("utf-8")

        return encrypted_msg

    @staticmethod
    def parse_xml_message(xml_str: str) -> Dict[str, str]:
        """
        解析XML格式的微信消息

        :param xml_str: XML字符串
        :return: 消息字典
        """
        try:
            root = ET.fromstring(xml_str)
            msg_dict = {}
            for child in root:
                msg_dict[child.tag] = child.text
            return msg_dict
        except ET.ParseError:
            print("❌ XML解析失败")
            return {}

    @staticmethod
    def build_xml_message(msg_dict: Dict[str, str]) -> str:
        """
        构建XML格式的微信消息

        :param msg_dict: 消息字典
        :return: XML字符串
        """
        root = ET.Element("xml")
        for key, value in msg_dict.items():
            child = ET.SubElement(root, key)
            child.text = value
        return ET.tostring(root, encoding="utf-8", xml_declaration=True).decode("utf-8")

    @staticmethod
    def generate_nonce_str(length: int = 16) -> str:
        """
        生成随机字符串

        :param length: 字符串长度
        :return: 随机字符串
        """
        chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
        return "".join(random.choice(chars) for _ in range(length))

    @staticmethod
    def generate_timestamp() -> str:
        """
        生成时间戳

        :return: 时间戳字符串
        """
        return str(int(time.time()))
