import requests
import time
import base64
import json

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

from app.models.gameservers import GameServer

from config import Config

config = Config()

def sign_content( content : bytes ) -> str:
    """
        Signs the given content using the gameserver private key

        :param content: The content to sign

        :returns: str
    """
    assert isinstance( content, bytes ), "content must be a bytes object"

    with open( config.GAMESERVER_COMM_PRIVATE_KEY_LOCATION, "rb" ) as f:
        private_key = serialization.load_pem_private_key(
            f.read(),
            password=None,
            backend=default_backend()
        )

    signature = private_key.sign(
        content,
        padding.PKCS1v15(),
        hashes.SHA256()
    )

    return base64.b64encode( signature ).decode( "utf-8" )

def perform_get(
    TargetGameserver : GameServer,
    Endpoint : str,
    AdditionalHeaders : dict = {},

    RequestTimeout : int = 10
) -> requests.Response:
    """
        Performs a GET request to the given gameserver

        :param TargetGameserver: The gameserver to send the request to
        :param Endpoint: The endpoint to send the request to
        :param AdditionalHeaders: Additional headers to send with the request
        :param RequestTimeout: The amount of time before the request times out

        :returns: requests.Response
    """
    assert isinstance( TargetGameserver, GameServer ), "TargetGameserver must be an instance of GameServer"
    assert isinstance( Endpoint, str ), "Endpoint must be a string"
    assert isinstance( AdditionalHeaders, dict ), "AdditionalHeaders must be a dictionary"

    RequestTimestamp = time.time()
    signed_content = sign_content( f'{RequestTimestamp}\nGET'.encode( 'utf-8' ) )
    ReqSignature = f"{str(RequestTimestamp)}|{ signed_content }"
    
    headers = {
        "User-Agent": "SYNTAX-Gameserver-Communication/1.0",
        "X-Syntax-Request-Signature": ReqSignature
    }

    return requests.get(
        url = f"http://{TargetGameserver.serverIP}:{TargetGameserver.serverPort}/{Endpoint}",
        headers = headers,
        timeout = RequestTimeout
    )

def perform_post(
    TargetGameserver : GameServer,
    Endpoint : str,
    JSONData : dict | list = {},
    AdditionalHeaders : dict = {},

    RequestTimeout : int = 10
) -> requests.Response:
    """
        Performs a POST request to the given gameserver

        :param TargetGameserver: The gameserver to send the request to
        :param Endpoint: The endpoint to send the request to
        :param JSONData: The JSON data to send with the request
        :param AdditionalHeaders: Additional headers to send with the request
        :param RequestTimeout: The amount of time before the request times out

        :returns: requests.Response
    """
    assert isinstance( TargetGameserver, GameServer ), "TargetGameserver must be an instance of GameServer"
    assert isinstance( Endpoint, str ), "Endpoint must be a string"
    assert isinstance( JSONData, ( dict, list ) ), "JSONData must be a dictionary or list"
    assert isinstance( AdditionalHeaders, dict ), "AdditionalHeaders must be a dictionary"

    RequestTimestamp = time.time()
    signed_content = sign_content( f"{RequestTimestamp}\nPOST\n{json.dumps(JSONData)}".encode( "utf-8" ))
    ReqSignature = f"{str(RequestTimestamp)}|{signed_content}"
    
    headers = {
        "User-Agent": "SYNTAX-Gameserver-Communication/1.0",
        "X-Syntax-Request-Signature": ReqSignature,
        "Content-Type": "application/json"
    }
    headers.update( AdditionalHeaders )

    return requests.post(
        url = f"http://{TargetGameserver.serverIP}:{TargetGameserver.serverPort}/{Endpoint}",
        headers = headers,
        data = json.dumps( JSONData ),
        timeout = RequestTimeout
    )