
from NGPIris.parse_credentials import CredentialsHandler
from NGPIris.hci.helpers import (
    get_index_response,
    get_query_response
)
from NGPIris.hci.exceptions import *

from requests import (
    Response,
    post
)
from urllib3 import disable_warnings
from json import load

class HCIHandler:
    def __init__(self, credentials_path : str, use_ssl : bool = False) -> None:
        """
        Class for handling HCI requests.

        :param credentials_path: Path to the JSON credentials file
        :type credentials_path: str

        :param use_ssl: Boolean choice between using SSL, defaults to False
        :type use_ssl: bool, optional
        """
        credentials_handler = CredentialsHandler(credentials_path)
        self.hci = credentials_handler.hci
        self.username = self.hci["username"]
        self.password = self.hci["password"]
        self.address = self.hci["address"]
        self.auth_port = self.hci["auth_port"]
        self.api_port = self.hci["api_port"]
        self.token = ""

        self.use_ssl = use_ssl

        if not self.use_ssl:
            disable_warnings()
    
    def request_token(self) -> None:
        """
        Request a token from the HCI, which is stored in the HCIHandler object. 
        The token is used for every operation that needs to send a request to 
        HCI.

        :raises VPNConnectionError: If there was a problem when requesting a token, a runtime error will be raised 
        """
        url = "https://" + self.address + ":" + self.auth_port + "/auth/oauth/"
        data = {
            "grant_type": "password", 
            "username": self.username, 
            "password": self.password,
            "scope": "*",  
            "client_secret": "hci-client", 
            "client_id": "hci-client", 
            "realm": "LOCAL"
        }
        try:
            response : Response = post(url, data = data, verify = self.use_ssl)
        except: # pragma: no cover
            error_msg : str = "The token request made at " + url + " failed. Please check your connection and that you have your VPN enabled"
            raise VPNConnectionError(error_msg) from None

        token : str = response.json()["access_token"]
        self.token = token

    def list_index_names(self) -> list[str]:
        """
        Retrieve a list of all index names.

        :return: A list of index names
        :rtype: list[str]
        """
        response : Response = get_index_response(self.address, self.api_port, self.token, self.use_ssl)
        return [entry["name"]for entry in response.json()]
    
    def look_up_index(self, index_name : str) -> dict:
        """
        Look up index information in the form of a dictionary by submitting 
        the index name. Will return an empty dictionary if no index was found.

        :param index_name: The index name
        :type index_name: str

        :return: A dictionary containing information about an index
        :rtype: dict
        """
        response : Response = get_index_response(self.address, self.api_port, self.token, self.use_ssl)

        for entry in response.json():
            if entry["name"] == index_name:
                return dict(entry)
        
        return {}

    def raw_query(self, query_dict : dict[str, str]) -> dict:
        """
        Make query to an HCI index, with a dictionary

        :param query_dict: Dictionary consisting of the query
        :type query_dict: dict[str, str]

        :return: Dictionary containing the raw query
        :rtype: dict
        """
        return dict(get_query_response(
            query_dict, 
            self.address, 
            self.api_port, 
            self.token, 
            self.use_ssl
        ).json())
            
    def raw_query_from_JSON(self, query_path : str) -> dict:
        """
        Make query to an HCI index, with prewritten query in a JSON file

        :param query_path: Path to the JSON file
        :type query_path: str

        :return: Dictionary containing the raw query
        :rtype: dict
        """
        with open(query_path, "r") as inp:
            return dict(get_query_response(
            dict(load(inp)), 
            self.address, 
            self.api_port, 
            self.token, 
            self.use_ssl
        ).json())