import hashlib
import json
import time
import urllib.parse
import requests
import struct

class MtopSignatureGenerator:
    def __init__(self, token, app_key="12574478", 
    # def __init__(self, token, app_key="24889839", 
                 api_name="mtop.relationrecommend.WirelessRecommend.recommend", 
                 api_version="2.0"):
        self.token = token
        self.app_key = app_key
        self.api_name = api_name
        self.api_version = api_version
    
    def _md5(self, input_string):
        """
        MD5 implementation that matches the JavaScript version in the HTML
        """
        # Convert string to UTF-8 bytes (equivalent to str2rstrUTF8 in JS)
        input_bytes = input_string.encode('utf-8')
        
        # Initialize variables (same as JavaScript)
        a = 1732584193
        b = -271733879
        c = -1732584194
        d = 271733878
        
        # Process the message in successive 512-bit chunks
        original_length = len(input_bytes)
        input_bytes += b'\x80'
        
        # Pad with zeros until message length in bits ≡ 448 (mod 512)
        while (len(input_bytes) * 8) % 512 != 448:
            input_bytes += b'\x00'
        
        # Append original length in bits mod 2^64 (little-endian)
        input_bytes += struct.pack('<Q', original_length * 8)
        
        # Process each 512-bit chunk
        for chunk_start in range(0, len(input_bytes), 64):
            chunk = input_bytes[chunk_start:chunk_start+64]
            words = [0] * 16
            
            # Break chunk into sixteen 32-bit words (little-endian)
            for i in range(16):
                words[i] = struct.unpack('<I', chunk[i*4:i*4+4])[0]
            
            # Save current state
            aa, bb, cc, dd = a, b, c, d
            
            # Round 1
            a = self._ff(a, b, c, d, words[0], 7, -680876936)
            d = self._ff(d, a, b, c, words[1], 12, -389564586)
            c = self._ff(c, d, a, b, words[2], 17, 606105819)
            b = self._ff(b, c, d, a, words[3], 22, -1044525330)
            a = self._ff(a, b, c, d, words[4], 7, -176418897)
            d = self._ff(d, a, b, c, words[5], 12, 1200080426)
            c = self._ff(c, d, a, b, words[6], 17, -1473231341)
            b = self._ff(b, c, d, a, words[7], 22, -45705983)
            a = self._ff(a, b, c, d, words[8], 7, 1770035416)
            d = self._ff(d, a, b, c, words[9], 12, -1958414417)
            c = self._ff(c, d, a, b, words[10], 17, -42063)
            b = self._ff(b, c, d, a, words[11], 22, -1990404162)
            a = self._ff(a, b, c, d, words[12], 7, 1804603682)
            d = self._ff(d, a, b, c, words[13], 12, -40341101)
            c = self._ff(c, d, a, b, words[14], 17, -1502002290)
            b = self._ff(b, c, d, a, words[15], 22, 1236535329)
            
            # Round 2
            a = self._gg(a, b, c, d, words[1], 5, -165796510)
            d = self._gg(d, a, b, c, words[6], 9, -1069501632)
            c = self._gg(c, d, a, b, words[11], 14, 643717713)
            b = self._gg(b, c, d, a, words[0], 20, -373897302)
            a = self._gg(a, b, c, d, words[5], 5, -701558691)
            d = self._gg(d, a, b, c, words[10], 9, 38016083)
            c = self._gg(c, d, a, b, words[15], 14, -660478335)
            b = self._gg(b, c, d, a, words[4], 20, -405537848)
            a = self._gg(a, b, c, d, words[9], 5, 568446438)
            d = self._gg(d, a, b, c, words[14], 9, -1019803690)
            c = self._gg(c, d, a, b, words[3], 14, -187363961)
            b = self._gg(b, c, d, a, words[8], 20, 1163531501)
            a = self._gg(a, b, c, d, words[13], 5, -1444681467)
            d = self._gg(d, a, b, c, words[2], 9, -51403784)
            c = self._gg(c, d, a, b, words[7], 14, 1735328473)
            b = self._gg(b, c, d, a, words[12], 20, -1926607734)
            
            # Round 3
            a = self._hh(a, b, c, d, words[5], 4, -378558)
            d = self._hh(d, a, b, c, words[8], 11, -2022574463)
            c = self._hh(c, d, a, b, words[11], 16, 1839030562)
            b = self._hh(b, c, d, a, words[14], 23, -35309556)
            a = self._hh(a, b, c, d, words[1], 4, -1530992060)
            d = self._hh(d, a, b, c, words[4], 11, 1272893353)
            c = self._hh(c, d, a, b, words[7], 16, -155497632)
            b = self._hh(b, c, d, a, words[10], 23, -1094730640)
            a = self._hh(a, b, c, d, words[13], 4, 681279174)
            d = self._hh(d, a, b, c, words[0], 11, -358537222)
            c = self._hh(c, d, a, b, words[3], 16, -722521979)
            b = self._hh(b, c, d, a, words[6], 23, 76029189)
            a = self._hh(a, b, c, d, words[9], 4, -640364487)
            d = self._hh(d, a, b, c, words[12], 11, -421815835)
            c = self._hh(c, d, a, b, words[15], 16, 530742520)
            b = self._hh(b, c, d, a, words[2], 23, -995338651)
            
            # Round 4
            a = self._ii(a, b, c, d, words[0], 6, -198630844)
            d = self._ii(d, a, b, c, words[7], 10, 1126891415)
            c = self._ii(c, d, a, b, words[14], 15, -1416354905)
            b = self._ii(b, c, d, a, words[5], 21, -57434055)
            a = self._ii(a, b, c, d, words[12], 6, 1700485571)
            d = self._ii(d, a, b, c, words[3], 10, -1894986606)
            c = self._ii(c, d, a, b, words[10], 15, -1051523)
            b = self._ii(b, c, d, a, words[1], 21, -2054922799)
            a = self._ii(a, b, c, d, words[8], 6, 1873313359)
            d = self._ii(d, a, b, c, words[15], 10, -30611744)
            c = self._ii(c, d, a, b, words[6], 15, -1560198380)
            b = self._ii(b, c, d, a, words[13], 21, 1309151649)
            a = self._ii(a, b, c, d, words[4], 6, -145523070)
            d = self._ii(d, a, b, c, words[11], 10, -1120210379)
            c = self._ii(c, d, a, b, words[2], 15, 718787259)
            b = self._ii(b, c, d, a, words[9], 21, -343485551)
            
            # Add this chunk's hash to result so far
            a = self._safe_add(a, aa)
            b = self._safe_add(b, bb)
            c = self._safe_add(c, cc)
            d = self._safe_add(d, dd)
        
        # Convert to little-endian byte array
        result = struct.pack('<4I', a, b, c, d)
        
        # Convert to hex string (equivalent to rstr2hex in JS)
        return ''.join(f'{b:02x}' for b in result)
    
    def _safe_add(self, x, y):
        """Add two 32-bit integers, wrapping at 2^32"""
        return (x + y) & 0xFFFFFFFF
    
    def _bit_rotate_left(self, num, cnt):
        """Bitwise rotate a 32-bit number to the left"""
        return ((num << cnt) | (num >> (32 - cnt))) & 0xFFFFFFFF
    
    def _ff(self, a, b, c, d, x, s, t):
        """FF transformation function"""
        a = self._safe_add(a, self._safe_add(self._safe_add(self._f(b, c, d), x), t))
        return self._safe_add(self._bit_rotate_left(a, s), b)
    
    def _gg(self, a, b, c, d, x, s, t):
        """GG transformation function"""
        a = self._safe_add(a, self._safe_add(self._safe_add(self._g(b, c, d), x), t))
        return self._safe_add(self._bit_rotate_left(a, s), b)
    
    def _hh(self, a, b, c, d, x, s, t):
        """HH transformation function"""
        a = self._safe_add(a, self._safe_add(self._safe_add(self._h(b, c, d), x), t))
        return self._safe_add(self._bit_rotate_left(a, s), b)
    
    def _ii(self, a, b, c, d, x, s, t):
        """II transformation function"""
        a = self._safe_add(a, self._safe_add(self._safe_add(self._i(b, c, d), x), t))
        return self._safe_add(self._bit_rotate_left(a, s), b)
    
    def _f(self, x, y, z):
        """F auxiliary function"""
        return (x & y) | ((~x) & z)
    
    def _g(self, x, y, z):
        """G auxiliary function"""
        return (x & z) | (y & (~z))
    
    def _h(self, x, y, z):
        """H auxiliary function"""
        return x ^ y ^ z
    
    def _i(self, x, y, z):
        """I auxiliary function"""
        return y ^ (x | (~z))
    
    def generate_signature(self, data):
        """Generate MTOP signature"""
        timestamp = str(int(time.time() * 1000))
        sign_content = f"{self.token}&{timestamp}&{self.app_key}&{json.dumps(data, ensure_ascii=False, separators=(',', ':'))}"
        return self._md5(sign_content), timestamp
    
    def generate_url(self, data):
        """Generate the full signed URL"""
        signature, timestamp = self.generate_signature(data)
        
        # Encode data for URL
        encoded_data = urllib.parse.quote(json.dumps(data, ensure_ascii=False, separators=(',', ':')))
        
        # Construct the URL
        # url = f"https://h5api.m.1688.com/h5/{self.api_name}/{self.api_version}/"
        # url = f"https://h5api.m.alibaba.com/h5/{self.api_name}/{self.api_version}/"
        url = f"https://h5api.m.alibaba.com/h5/mtop.alibaba.goods.searchservice.getsearchresult/1.0/"
        # params = {
        #     "jsv": "2.7.4",
        #     "appKey": self.app_key,
        #     "t": timestamp,
        #     "sign": signature,
        #     "api": self.api_name,
        #     "v": self.api_version,
        #     "dataType": "json",
        #     "type": "originaljson",
        #     "data": encoded_data
        # }
        # API parameters for Alibaba (different from 1688)
        params = {
            'jsv': '2.5.1',
            'appKey': '12574478',
            "t": timestamp,
            "sign": signature,
            'api': 'mtop.alibaba.goods.searchservice.getsearchresult',
            'v': '1.0',
            'type': 'json',
            'dataType': 'json',
            'timeout': '20000',
            "data": encoded_data

        }
        
        # Build query string
        query_string = "&".join([f"{k}={v}" for k, v in params.items()])
        return f"{url}?{query_string}", signature, timestamp
    
    # def make_request(self, data):
    #     """Make the API request and return the response"""
    #     url, signature, timestamp = self.generate_url(data)
        
    #     headers = {
    #         "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
    #         "Accept": "application/json",
    #         "Accept-Language": "en-US,en;q=0.9",
    #         "Referer": "https://www.1688.com/",
    #         "Origin": "https://www.1688.com"
    #     }
        
    #     try:
    #         response = requests.get(url, headers=headers, timeout=30)
    #         return response.json()
    #     except requests.exceptions.RequestException as e:
    #         return {"error": str(e)}
    #     except json.JSONDecodeError as e:
    #         return {"error": f"JSON decode error: {str(e)}"}


def main():
    # Your token from _m_h5_tk cookie (without the underscore and timestamp part)
    token = "2a7ed03ca270d30a90aeccfe8ee821ab"  # Replace with your actual token
    
    # Request data (same as in the HTML example)
    request_data = {
        "appId": 32517,
        # "appId": 337938,
        "params": "{\"verticalProductFlag\":\"pcmarket\",\"searchScene\":\"pcOfferSearch\",\"charset\":\"GBK\",\"beginPage\":1, \"pageSize\":60,\"keywords\":\"iphone15\",\"spm\":\"a260k.home2025.searchbox.0\",\"method\":\"getOfferList\"}"
    }
    
    if not token or token == "YOUR_TOKEN_HERE":
        print("Error: Please provide a valid token")
        print("To get your token:")
        print("1. Visit 1688.com in your browser")
        print("2. Open Developer Tools (F12)")
        print("3. Go to Application/Storage tab → Cookies")
        print("4. Find the _m_h5_tk cookie and copy the part before the underscore")
        return
    
    # Initialize the generator
    generator = MtopSignatureGenerator(token)
    
    # Generate the URL
    url, signature, timestamp = generator.generate_url(request_data)
    
    print("Generated URL:")
    print(url)
    print("\nSignature:")
    print(signature)
    print("\nTimestamp:")
    print(timestamp)
    
    # Make the API request
    print("\nMaking API request...")
    # response = generator.make_request(request_data)
    
    print("\nAPI Response:")
    # print(json.dumps(response, indent=2, ensure_ascii=False))
    
    # Debug: Show what was sent for signature generation
    debug_data = {
        "token": token,
        "timestamp": timestamp,
        "app_key": generator.app_key,
        "data": request_data,
        "sign_content": f"{token}&{timestamp}&{generator.app_key}&{json.dumps(request_data, ensure_ascii=False, separators=(',', ':'))}"
    }
    print("\nDebug Information:")
    print(json.dumps(debug_data, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    main()