from urllib.parse import urljoin

import requests
from requests.exceptions import RequestException

from src.qwikswitchapi.constants import Constants
from src.qwikswitchapi.entities.apikeys import ApiKeys
from src.qwikswitchapi.entities.controlresult import ControlResult
from src.qwikswitchapi.entities.devicestatuses import DeviceStatuses
from src.qwikswitchapi.utility.responseparser import ResponseParser
from src.qwikswitchapi.utility.urlbuilder import UrlBuilder


class QSApi:

    def __init__(self, base_uri:str=Constants.DEFAULT_BASE_URI):
        """
        Initializes a new instance of the QSApi class

        :param base_uri: the base URI of the Qwikswitch API, optional.  Defaults to 'https://qwikswitch.com/api/v1/'
        """

        if not base_uri.endswith('/'):
            base_uri += '/'

        self._base_uri = base_uri

    @property
    def base_uri(self) -> str:
        """
        The base URI of the Qwikswitch API

        :returns: The base URI of the Qwikswitch API
        """

        return self._base_uri

    def generate_api_keys(self, email:str, master_key:str,) -> ApiKeys:
        """
        Generates API keys for the given email and master key to be used in subsequent calls

        :param email: the email address to generate API keys for:param email: your email address registered on https://qwikswitch.com
        :param master_key: 12 character key found under your CloudHub.  This should be your device id of your Qwikswitch Wi-Fi bridge.
        :returns: APIKeys, with an API key for read operations, and one for read-write operations.
        :raises QSException: on failure to generate API keys
        """

        url = UrlBuilder.build_generate_api_keys_url(self._base_uri)
        req = {
            Constants.JsonKeys.EMAIL: email,
            Constants.JsonKeys.MASTER_KEY: master_key
        }

        try:
            resp = requests.post(url, json=req)
            return ApiKeys.from_resp(resp)
        except RequestException as ex:
            ResponseParser.raise_request_failure(url, ex)

    def delete_api_keys(self, email: str, master_key: str) -> None:
        """
        Deletes API keys generated for the given email and master key

        :param email: the email address to generate API keys for:param email: your email address registered on https://qwikswitch.com
        :param master_key: 12 character key found under your CloudHub.  This should be your device id of your Qwikswitch Wi-Fi bridge.
        :returns: None
        :raises QSException: on failure to delete API keys
        """

        url = UrlBuilder.build_delete_api_keys_url(self._base_uri)
        req = {
            Constants.JsonKeys.EMAIL: email,
            Constants.JsonKeys.MASTER_KEY: master_key
        }

        try:
            resp = requests.post(url, json=req)
            parsed_response = ApiKeys.from_resp(resp)
        except RequestException as ex:
            ResponseParser.raise_request_failure(url, ex)

    def control_device(self, auth:ApiKeys, device_id:str, level:int) -> ControlResult:
        """
        Controls a device by setting the desired level.

        :param auth: authentication keys generated by generate_api_keys
        :param device_id: the unique identifier of the device to control
        :param level: this is a description of what is returned
        :returns: ControlResult, with the device and level set
        :raises QSException: when the request fails
        """

        url = UrlBuilder.build_control_url(auth.read_write_key, device_id, level, self._base_uri)

        try:
            resp = requests.get(url)
            return ControlResult.from_resp(resp)
        except RequestException as ex:
            ResponseParser.raise_request_failure(url, ex)

    def get_all_device_status(self, auth:ApiKeys) -> DeviceStatuses:
        """
        Retrieves the status of all devices registered to the given API keys

        :param auth: authentication keys generated by generate_api_keys
        :returns: Array of DeviceStatus with device information
        :raises QSException: when the request fails
        """

        url = UrlBuilder.build_get_all_device_status_url(auth.read_write_key, self._base_uri)

        try:
            resp = requests.get(url)
            return DeviceStatuses.from_resp(resp)
        except RequestException as ex:
            ResponseParser.raise_request_failure(url, ex)



