import json
import logging
import requests

try:
    # python 2
    from urlparse import urljoin
except ImportError:
    # python3
    from urllib.parse import urljoin

try:
    from collections import OrderedDict
except ImportError:
    # python 2.6 or earlier, use backport
    from ordereddict import OrderedDict

from .config import *


class FosDickAPIException(Exception):
    pass


class FosDickAPIUnavailable(FosDickAPIException):
    def __init__(self, url, message=None):
        self.message = message or "API is unavailable"
        self.url = url

    def __str__(self):
        return self.message


class FosDickAPIRequestError(FosDickAPIException):
    def __init__(self, message):
        super(FosDickAPIRequestError, self).__init__(message)


class FosDickAPI(object):
    """
    This class will interact with fostdick api's for pulling information
    about shipments, inventory, receipts etc.
    """
    # sets "init'ial" state .
    def __init__(self, username=None, password=None):
        self.USERNAME = username or FOSDICK_API_USERNAME
        self.PASSWORD = password or FOSDICK_API_PASSWORD
        self.URL = URL

    def _get_url(self, pathname):
        """
        For each pathname return corresponding URL.
        :param pathname:
        :return:
        """

        return urljoin(self.URL, pathname)

    def _create_request(self, action, **kwargs):
        """
        Used to create the request_url and query params.
        :param action: action
        :param kwargs:
        :return: request_url, data
        """
        data = dict()
        data.update(kwargs)
        req_url = URL_MAP.get(action, '/')
        request_url = self._get_url(req_url)
        return request_url, data

    def _get_response(self, request_url, data):
        """
        Perform json-request to API
        :param request_url: Absolute url to API.
        :type request_url: str
        :param data: Datas to send to the API.
        :type data: dict
        :return: json response
        :rtype: dict
        """
        # To authenticate the request.
        auth = (self.USERNAME, self.PASSWORD)
        try:
            req = requests.get(
                request_url,
                params=data,
                auth=auth
            )
            content = req.content
            logging.debug(content)
        except requests.exceptions.RequestException as e:
            # API not available.
            raise FosDickAPIUnavailable(self.URL, str(e))
        try:
            json_response = req.json()
        except Exception as e:
            raise FosDickAPIRequestError(str(e))
        return json_response

    def request(self, action, **kwargs):
        """
        Perform json-request to API
        :param action: method action (name of the function in API)
        :type action: str
        :return: json response
        :rtype: dict
        """
        request_url, data = self._create_request(
            action, **kwargs)
        try:
            json_response = self._get_response(request_url, data)
        except Exception as e:
            raise FosDickAPIException(str(e))
        # if No response
        if not json_response:
            return []

        return json_response

    def get_shipments(self, **kwargs):
        """
        :param kwargs:page,
                per_page,
                updated_at_min,
                updated_at_max,
                shipped_on_min,
                shipped_on_max,
                fosdick_order_num,
                external_order_num
        :return: list of shipped orders
        """
        shipment_info = self.request(action='shipments', **kwargs)
        return shipment_info

    def get_inventory(self, **kwargs):
        """
        :param kwargs:page,
                per_page,
                updated_at_min,
                updated_at_max.
        :return: List of inventory levels for products
        """
        inventory_info = self.request(action='inventory', **kwargs)
        return inventory_info

    def get_all_returns(self, **kwargs):
        """
        :param kwargs:page,
                    per_page,
                    updated_at_min,
                    updated_at_max,
                    returned_at_min,
                    returned_at_max.
        :return:List of returned orders/items
        """