import json
import zlib
import pytz
import hashlib
import requests

from binascii import unhexlify, hexlify
import socket
import re

from datetime import datetime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

AesKey = "A;mv5YUpHBK3YxTy5KB^[;5]C2AL50Bq"
AesIV = "9FM:sd9xA91X14v]"
ObfuscateParam = "M9aBNKuY"

class aes_pkcs7(object):
    def __init__(self, key: str, iv: str):
        self.key = key.encode('utf-8')
        self.iv = iv.encode('utf-8')
        self.mode = AES.MODE_CBC

    def encrypt(self, content: bytes) -> bytes:
        cipher = AES.new(self.key, self.mode, self.iv)
        content_padded = pad(content, AES.block_size)
        encrypted_bytes = cipher.encrypt(content_padded)
        return encrypted_bytes

    def decrypt(self, content):
        cipher = AES.new(self.key, self.mode, self.iv)
        decrypted_padded = cipher.decrypt(content)
        decrypted = unpad(decrypted_padded, AES.block_size)
        return decrypted

    def pkcs7unpadding(self, text):
        length = len(text)
        unpadding = ord(text[length - 1])
        return text[0:length - unpadding]

    def pkcs7padding(self, text):
        bs = 16
        length = len(text)
        bytes_length = len(text.encode('utf-8'))
        padding_size = length if (bytes_length == length) else bytes_length
        padding = bs - padding_size % bs
        padding_text = chr(padding) * padding
        return text + padding_text

def get_hash_api(api):
    return hashlib.md5((api+"MaimaiExp"+ObfuscateParam).encode()).hexdigest()

def sdgb_api(data, useApi, userId):
    aes = aes_pkcs7(AesKey,AesIV)
    data = bytes(data, encoding="utf-8")
    data_def = zlib.compress(data)
    data_enc = aes.encrypt(data_def)
    endpoint = "https://mai2exp.sic-rd1.jp:42081/Maimai2Servlet/"
    requests.packages.urllib3.disable_warnings()
    r = requests.post(
        endpoint + get_hash_api(useApi),
        headers = {
            "User-Agent": "%s#%d"%(get_hash_api(useApi), userId), 
            "Content-Type": "application/json",
            "Mai-Encoding": "1.51",
            "Accept-Encoding": "",
            "Charset": "UTF-8", 
            "Content-Encoding": "deflate", 
            "Expect": "100-continue"
        },
        data = data_enc
    )
    resp_enc = r.content
    try:
        resp_def = aes.decrypt(resp_enc)
    except:
        resp_def = resp_enc
    return zlib.decompress(resp_def).decode('utf-8')

def felica(IDm):
    key = b'Copyright(C)SEGA'
    # https://sega.bsnk.me/allnet/aimedb/common/
    magic = "3ea1"
    version = "2140"
    command_id = "0100" # ID = 1
    length = "3000" # 48
    gameId = "534447410000" # SDGA
    storeId = "bc310000"
    keychip_ID = "413633453031453032363400" # A63E01E0264
    header = magic + version + command_id + length + "0000" + gameId + storeId + keychip_ID

    IDm = str(IDm)
    PMm = "00F1000000014300"

    plaintext_hex_stream = header + IDm + PMm

    plaintext = unhexlify(plaintext_hex_stream)

    cipher = AES.new(key, AES.MODE_ECB)
    encrypted_message = cipher.encrypt(plaintext)

    encrypted_hex_stream = hexlify(encrypted_message).decode('utf-8')

    server_address = ('aime.naominet.jp', 22345)
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect(server_address)
        sock.sendall(encrypted_message)

        response = sock.recv(1024)

        decrypted_response = cipher.decrypt(response)

        decrypted_hex_stream = hexlify(decrypted_response).decode('utf-8')

    return decrypted_hex_stream

def aimedb_api(accessCode):
    key = b'Copyright(C)SEGA'
    # https://sega.bsnk.me/allnet/aimedb/common/
    magic = "3ea1"
    version = "2140"
    command_id = "0f00" # ID = 15
    length = "3000" # 48
    gameId = "534447410000" # SDGA
    storeId = "bc310000"
    keychip_ID = "413633453031453032363400" # A63E01E0264
    header = magic + version + command_id + length + "0000" + gameId + storeId + keychip_ID

    access_code = str(accessCode)
    end_stream = "000201020304"


    plaintext_hex_stream = header + access_code + end_stream

    plaintext = unhexlify(plaintext_hex_stream)

    cipher = AES.new(key, AES.MODE_ECB)
    encrypted_message = cipher.encrypt(plaintext)

    encrypted_hex_stream = hexlify(encrypted_message).decode('utf-8')

    server_address = ('aime.naominet.jp', 22345)
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect(server_address)
        sock.sendall(encrypted_message)

        response = sock.recv(1024)

        decrypted_response = cipher.decrypt(response)

        decrypted_hex_stream = hexlify(decrypted_response).decode('utf-8')

        match = re.search(r'[0-9a-f]{64}([0-9a-f]{6})', decrypted_hex_stream)
        if match:
            six_digit_code = match.group(1)

            rearranged_hex = six_digit_code[4:6] + six_digit_code[2:4] + six_digit_code[0:2]
    
            decimal_value = int(rearranged_hex, 16)
            return decimal_value
