from logging import Logger
from typing import (
    Dict,
    List,
    Optional,
    Tuple,
)

import requests
from requests import Response

from helper import retry

from services.model import (
    Configs,
    ForbiddenError,
    InUseError,
    NotAvailableError,
    NotFound,
    NotFoundError,
    NoResponseError,
    ProcessorError,
)
from services.util import (
    get_store_id,
    get_boh_url,
    get_boh_api_key,
)


class AlertsAPIRepository(object):

    def __init__(
        self,
        configs,  # type: Configs
        logger,   # type: Logger
    ):
        # type: (...) -> None

        self.logger = logger
        self.configs = configs

    def retrieve_configured_alerts(
        self,
    ):
        # type: (...) -> Optional[str, Exception]

        try:
            url = "{}{}".format(
                get_boh_url(),
                self.configs.alerts["EndPoints"]["ConfiguredAlerts"],
            )
            url = url.format(storeId=get_store_id())
            headers = self._get_headers()
            errors_list = []

            response = retry(
                logger=self.logger,
                method_name="retrieve_configured_alerts",
                n=1,
                sleep_seconds=1,
                trying_to_do=lambda: requests.request("GET", url=url, headers=headers, timeout=20),
                is_success=lambda resp: resp.status_code == 200,
                success=lambda resp: resp,
                failed=lambda resp: errors_list.append((resp.status_code, resp))
            )
            if response:
                return response.content

            if not errors_list:
                raise NotFound()

            response_error = self._get_response_error(errors_list)
            self._raise_lock_custom_exception(
                response_error.status_code,
                response_error
            )
        except Exception as _:  # noqa
            self.logger.exception("Error retrieving configured alerts")
            raise

    @staticmethod
    def _get_headers(
    ):
        # type: (...) -> Dict

        headers = {
            "X-Api-Key": get_boh_api_key(),
            "Content-type": "application/json",
        }
        return headers

    def _raise_lock_custom_exception(
        self,
        status_code,     # type: int
        response_error,  # type: Response
    ):
        # type: (...) -> None

        if status_code == 204:
            raise NoResponseError(self.logger, response_error)
        if status_code == 403:
            raise ForbiddenError(self.logger, response_error)
        if status_code == 404:
            raise NotFoundError(self.logger, response_error)
        if status_code == 406:
            raise NotAvailableError(self.logger, response_error)
        if status_code == 409:
            raise InUseError(self.logger, response_error)
        if status_code >= 500:
            raise ProcessorError(self.logger, response_error)

    @staticmethod
    def _get_response_error(
        errors_list,  # type: List[Tuple]
    ):
        # type: (...) -> Response

        last_error = errors_list[-1]
        status_code, response = last_error
        return response
