from urllib.parse import quote, unquote
import requests
from Crypto.Cipher import AES, PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Util.Padding import pad, unpad
import base64
import hashlib
import json
import time


def send_data(url: str, data: str,client_public_key: str = '', server_private_key: str = '') -> str:
    """
    发送数据包
    :param url: 服务器地址
    :param data: 请求内容 (已含appsafecode的urlencoded参数字符串)
    :param client_public_key: RSA公钥，用于加密签名(新加密算法必填)
    :param server_private_key: RSA私钥，用于解密响应签名(新加密算法必填)
    :return: 返回数据明文
    """
    try:
        request_data = data
        print("request_data:", request_data)


        # 先用AES-128-CBC 随机密码 加密数据
        time_md5 = hashlib.md5(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()).encode()).hexdigest()
        aes_key = hashlib.md5((server_private_key + time_md5).encode()).hexdigest()[:16]
        iv = aes_key.encode('utf-8')
        cipher = AES.new(aes_key.encode('utf-8'), AES.MODE_CBC, iv)
        padded = pad(request_data.encode('utf-8'), AES.block_size)
        encrypted_bytes = cipher.encrypt(padded)
        encrypted_b64 = base64.b64encode(encrypted_bytes).decode()
       
        print("encrypted_b64:", encrypted_b64)
        print("aes_key:", aes_key)
        #2.rsa加密签名内容 “0|AES-128-CBC|” ＋ AES密钥 ＋ “|” ＋ 取数据摘要_MD5 (到字节集 (发送加密数据)) ＋ “|json”
        signature_content = f"0|AES-128-CBC|{aes_key}|{hashlib.md5(encrypted_b64.encode('utf-8')).hexdigest()}|json"
        signature_bytes = signature_content.encode('utf-8')
        rsa_cipher = PKCS1_v1_5.new(_import_rsa_key(client_public_key, public=True))
        rsa_encrypted = rsa_cipher.encrypt(signature_bytes)
        rsa_b64 = base64.b64encode(rsa_encrypted).decode()
        print("rsa_b64:", rsa_b64)

        request_data = encrypted_b64 + '|' + rsa_b64
        print("request_data:", request_data)
        #url编码
        request_data = quote(request_data, safe='')
        print("request_data:", request_data)

        result = requests.post(url, data={"parameter": request_data})
        print("result:", result)
        print("return body:", result.text)

        if result.status_code != 200 or not result.text:
            print("send_data: 服务器返回异常 status=%s body为空" % result.status_code)
            return ''

        result_text = _decrypt_v2(result.text, server_private_key)
        print("result_text:", result_text)
        if not result_text:
            return ''
        json_loads = json.loads(result_text)
        print("result_json_loads:", json_loads['response'])
        return json_loads['response']
    except Exception as e:
        print("send_data error:", e)
        return ''


def _import_rsa_key(key_data, public=True):
    """导入 RSA 密钥，支持 PEM 或 base64 DER 格式"""
    try:
        return RSA.import_key(key_data)
    except (ValueError, IndexError, TypeError):
        try:
            key_bytes = key_data.encode() if isinstance(key_data, str) else key_data
            return RSA.import_key(base64.b64decode(key_bytes))
        except Exception:
            raise


def _extract_appsafecode(data: str) -> str:
    """从 urlencoded 参数字符串中提取 appsafecode"""
    from urllib.parse import parse_qs
    try:
        params = parse_qs(data)
        return params.get('appsafecode', [hashlib.md5(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()).encode()).hexdigest()])[0]
    except:
        return hashlib.md5(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()).encode()).hexdigest()


def _encrypt_v2(data: str, mutual_key: str, client_public_key_pem: str, appsafecode: str) -> str:
    """
    新加密算法(易语言兼容):
    1. AES密钥 = MD5(通信密码 + appsafecode)，取前16字符为key和iv
    2. AES-128-CBC 加密数据，Base64
    3. 签名内容 = "0|AES-128-CBC|" + AES密钥 + "|" + MD5(加密数据) + "|json"
    4. RSA公钥加密签名内容，Base64
    5. 返回: 加密数据 + "|" + RSA签名
    """
    try:
        data_utf8 = data.encode('utf-8')

        # 2. AES密钥
        aes_key_full = hashlib.md5((mutual_key + appsafecode).encode()).hexdigest()
        aes_key = aes_key_full[:16]
        iv = aes_key.encode('utf-8')

        # 3. AES-128-CBC 加密
        cipher = AES.new(aes_key.encode('utf-8'), AES.MODE_CBC, iv)
        padded = pad(data_utf8, AES.block_size)
        encrypted_bytes = cipher.encrypt(padded)
        encrypted_b64 = base64.b64encode(encrypted_bytes).decode()

        # 4. 签名内容
        encrypted_for_md5 = encrypted_b64.encode('utf-8')
        sig_md5 = hashlib.md5(encrypted_for_md5).hexdigest()
        signature_content = f"0|AES-128-CBC|{aes_key_full}|{sig_md5}|json"
        signature_bytes = signature_content.encode('utf-8')

        # 5. RSA 公钥加密
        pub_key = _import_rsa_key(client_public_key_pem, public=True)
        rsa_cipher = PKCS1_v1_5.new(pub_key)
        rsa_encrypted = rsa_cipher.encrypt(signature_bytes)
        rsa_b64 = base64.b64encode(rsa_encrypted).decode()

        # 6. 最终: 加密数据|RSA签名
        return encrypted_b64 + '|' + rsa_b64
    except Exception as e:
        print("_encrypt_v2 error:", e)
        return None


def _decrypt_v2(response_text: str, server_private_key_pem: str) -> str:
    """
    新解密(易语言兼容):
    响应格式: 加密数据|RSA签名
    RSA解密签名得到: 0|AES-CBC|key|md5|...
    用 key 前16字符做 AES-CBC 解密
    """
    try:
        # URL 解码
        raw = unquote(response_text)
        parts = raw.split('|')
        if len(parts) < 3:
            return response_text
        encrypted_b64 = parts[1].strip()
        rsa_b64 = parts[2].strip()

        # RSA 解密签名
        priv_key = _import_rsa_key(server_private_key_pem, public=False)
        rsa_cipher = PKCS1_v1_5.new(priv_key)
        sig_decrypted = rsa_cipher.decrypt(base64.b64decode(rsa_b64), sentinel=b'')
        if sig_decrypted == b'':
            return response_text
        sig_str = sig_decrypted.decode('utf-8')
        sig_parts = sig_str.split('|')
        if len(sig_parts) < 4:
            return response_text
        aes_key_full = sig_parts[2]
        aes_key = aes_key_full[:16]
        iv = aes_key.encode('utf-8')

        # AES 解密
        cipher = AES.new(aes_key.encode('utf-8'), AES.MODE_CBC, iv)
        ct = base64.b64decode(encrypted_b64)
        pt = unpad(cipher.decrypt(ct), AES.block_size)
        return pt.decode('utf-8')
    except Exception as e:
        print("_decrypt_v2 error:", e)
        return response_text


def _encrypt(data: str, key: str):
    """
    AES-ECB加密 (旧算法)
    """
    try:
        key = hashlib.md5(key.encode('utf-8')).hexdigest()[:16]
        cryptor = AES.new(key.encode('utf-8'), AES.MODE_ECB)
        padded_data = pad(data.encode("utf-8"), AES.block_size)
        return base64.b64encode(cryptor.encrypt(padded_data)).decode()
    except:
        return None


def _unpad(data: bytes):
    """去掉和php不兼容的padding"""
    return data[:-data[-1]].decode('utf-8')


def _decrypt(data: str, key: str):
    """
    AES-ECB解密 (旧算法)
    """
    try:
        text = base64.b64decode(data)
        key = hashlib.md5(key.encode('utf-8')).hexdigest()[:16]
        cryptor = AES.new(key.encode('utf-8'), AES.MODE_ECB)
        return _unpad(cryptor.decrypt(text))
    except:
        return None


def get_middle_str(content: str, start_str: str, end_str: str) -> str:
    start_index = content.index(start_str)
    if start_index >= 0:
        start_index += len(start_str)
    end_index = content.index(end_str)
    return content[start_index:end_index]


if __name__ == '__main__':
    data = _encrypt("123123213123", "91wGnIQVkNxIQmeUWK")
    result = _decrypt(data, "91wGnIQVkNxIQmeUWK")
    print('结果', result)
