# global import, red is normal don't worry
import network_constants

import requests
import json
from typing import Dict, List

class TokenStash:
    '''
    used to keep track of already verified tokens in order to mitigate the traffic
    to the user-microservice
    '''
    trusted_tokens = {}
    roles = {}

    @staticmethod
    def add(token: str, username: str, role: str):
        '''
        adds a verified token to the stash
        '''
        TokenStash.trusted_tokens[token] = username
        TokenStash.roles[token] = role

    @staticmethod
    def is_token_cached(token: str) -> str:
        '''
        returns the associated username to a token, None otherwise
        '''

        if token in TokenStash.trusted_tokens and token in TokenStash.roles:
            return {"sub": TokenStash.trusted_tokens[token], "role": TokenStash.roles[token]}

        return None


def decodeToken(token: str, roles:List[str]=[]) -> Dict:
    '''
    verifies the passed token on the user-microservice and returns a dictionary with the
    subject entry if the verification was successful, an error is raised otherwise

    @params:
            token - Required : JWT token from authorization header, must start with "Bearer "
            roles - Optional : User must have at least one of these roles
    '''

    if not token.startswith("Bearer "):
        raise ValueError('Invalid JWT token (must be a Bearer string)')
    token = token[7:]

    cached_data = TokenStash.is_token_cached(token)
    if cached_data != None:
        # Re-Use cached token
        return cached_data

    url = f'https://{network_constants.REST_GATEWAY_HOSTNAME}:{network_constants.REST_GATEWAY_REST_PORT}/api/tokens/{token}'

    response = requests.post(
            url,
            verify=False, 
            # proxies = { "http":"http://proxy.uni-klu.ac.at:3128/", "https":"http://proxy.uni-klu.ac.at:3128/" }
            )

    if response.status_code != 200:
        raise ValueError(
            f"Validation of token failed ({response.status_code})!")

    data = json.loads(response.text)

    if not "username" in data or not "role" in data:
        raise ValueError(
            f"Validation of token failed (missing field in verification response)!")
    
    if len(roles) > 0 and data["role"] not in roles:
        raise ValueError(
            f"Validation of token failed (wrong role)!")

    TokenStash.add(token, data["username"], data["role"])
    return {"sub": data["username"], "role": data["role"]}
