"""Base StarLine API."""
import logging
import requests
from datetime import datetime
from typing import Optional
from .const import DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT, DEFAULT_ENCODING, GET, POST

_LOGGER = logging.getLogger(__name__)


class BaseApi:
    """Base StarLine API class."""

    def __init__(self):
        """Constructor."""
        self._session: requests.Session = requests.Session()
        self._connect_timeout: int = DEFAULT_CONNECT_TIMEOUT
        self._read_timeout: int = DEFAULT_READ_TIMEOUT
        self._encoding: str = DEFAULT_ENCODING

    def set_timeout(self, read_timeout: int, connect_timeout: int = None) -> None:
        """Set connection timeouts."""
        self._read_timeout = read_timeout
        if connect_timeout is not None:
            self._connect_timeout = connect_timeout

    def set_encoding(self, encoding: str) -> None:
        """Set response encoding."""
        self._encoding = encoding

    def _request(self, method: str, url: str, params: dict = None, data: dict = None, json: dict = None, headers: dict = None) -> Optional[requests.Response]:
        """Make request."""

        try:
            response = self._session.request(
                method,
                url,
                params=params,
                data=data,
                json=json,
                headers=headers,
                timeout=(self._connect_timeout, self._read_timeout),
            )
            response.encoding = self._encoding
            response.raise_for_status()

            _LOGGER.debug("StarlineApi {} request: {}".format(method, url))
            _LOGGER.debug("  Payload: {}".format(params))
            _LOGGER.debug("  Data: {}".format(data))
            _LOGGER.debug("  JSON: {}".format(json))
            _LOGGER.debug("  Headers: {}".format(headers))
            _LOGGER.debug("  Response: {}".format(response))

            return response
        except requests.exceptions.RequestException as error:
            _LOGGER.error("Request failed: %s", error)
            return None

    def _get(self, url: str, params: dict = None, headers: dict = None) -> Optional[dict]:
        """Make GET request."""

        response = self._request(GET, url, params=params, headers=headers)
        if response is None:
            return None

        data = response.json()
        _LOGGER.debug("  Data: {}".format(data))
        return data

    def _post(self, url: str, params: dict = None, data: dict = None, json: dict = None, headers: dict = None) -> Optional[dict]:
        """Make POST request."""

        response = self._request(POST, url, params=params, data=data, json=json, headers=headers)
        if response is None:
            return None

        data = response.json()
        _LOGGER.debug("  Data: {}".format(data))
        return data

    def get_user_id(self, slid_token: str) -> (str, float, str):
        """Authenticate user by StarLineID token."""

        url = "https://developer.starline.ru/json/v2/auth.slid"
        data = {"slid_token": slid_token}
        response = self._request(POST, url, json=data)
        if response is None:
            raise Exception("Failed to get SLNet token")

        json = response.json()
        if int(json["code"]) != 200:
            raise Exception(json["codestring"])

        slnet_token = None
        expires_time = datetime.now().timestamp() + (4 * 60 * 60)  # Now + 4h
        for cookie in response.cookies:
            if cookie.name == 'slnet':
                slnet_token = cookie.value
                expires_time = cookie.expires

        if slnet_token is None:
            raise Exception("Failed to get SLNet token")

        _LOGGER.debug("SLNet token: {}".format(slnet_token))
        return slnet_token, expires_time, json["user_id"]
