# © 2019-2021 Hibou Corp.

import requests
from urllib.parse import urlencode
from json import loads, dumps
from json.decoder import JSONDecodeError

import logging
_logger = logging.getLogger(__name__)


class Opencart:

    def __init__(self, base_url, restadmin_token):
        self.base_url = str(base_url) + '/api/rest_admin/'
        self.restadmin_token = restadmin_token
        self.session = requests.Session()
        self.session.headers['X-Oc-Restadmin-Id'] = self.restadmin_token

    @property
    def orders(self):
        return Orders(connection=self)

    @property
    def stores(self):
        return Stores(connection=self)

    @property
    def products(self):
        return Products(connection=self)

    def get_headers(self, url, method):
        headers = {}
        if method in ('POST', 'PUT', ):
            headers['Content-Type'] = 'application/json'
        return headers

    def send_request(self, method, url, params=None, body=None):
        encoded_url = url
        if params:
            encoded_url += '?%s' % urlencode(params)
        headers = self.get_headers(encoded_url, method)
        _logger.debug('send_request method: %s url: %s headers: %s params: %s body: %s' % (
            method,
            url,
            headers,
            params,
            body
        ))
        if method == 'GET':
            result_text = self.session.get(url, params=params, headers=headers).text
        elif method == 'PUT' or method == 'POST':
            result_text = self.session.put(url, data=body, headers=headers).text
        _logger.debug('raw_text: ' + str(result_text))
        try:
            return loads(result_text)
        except JSONDecodeError:
            return {}


class Resource:
    """
    A base class for all Resources to extend
    """

    def __init__(self, connection):
        self.connection = connection

    @property
    def url(self):
        return self.connection.base_url + self.path


class Orders(Resource):
    """
    Retrieves Order details
    """

    path = 'orders'

    def all(self, id_larger_than=None, modified_from=None):
        url = self.url
        if id_larger_than:
            url += '/id_larger_than/%s' % id_larger_than
        if modified_from:
            url += '/modified_from/%s' % modified_from
        return self.connection.send_request(method='GET', url=url)

    def get(self, id):
        url = self.url + ('/%s' % id)
        return self.connection.send_request(method='GET', url=url)

    def ship(self, id, tracking, tracking_comment=None):
        def url(stem):
            return self.connection.base_url + ('%s/%s' % (stem, id))
        res = self.connection.send_request(method='PUT', url=url('trackingnumber'), body=self.get_tracking_payload(tracking))
        if tracking_comment:
            res = self.connection.send_request(method='PUT', url=url('orderhistory'), body=self.get_orderhistory_payload(
                3,  # "Shipped"
                True,  # Notify!
                tracking_comment,
            ))
        return res

    def cancel(self, id):
        url = self.connection.base_url + ('order_status/%s' % id)
        return self.connection.send_request(method='POST', url=url, body=self.get_status_payload('Canceled'))

    def get_status_payload(self, status):
        """
        {
          "status": "Canceled"
        }
        """
        payload = {
            "status": status,
        }
        return dumps(payload)

    def get_tracking_payload(self, tracking):
        """
        {
          "tracking": "5559994444"
        }
        """
        payload = {
            "tracking": tracking,
        }
        return dumps(payload)

    def get_orderhistory_payload(self, status_id, notify, comment):
        """
        {
          "order_status_id": "5",
          "notify": "1",
          "comment": "demo comment"
        }
        """
        payload = {
            'order_status_id': str(status_id),
            'notify': '1' if notify else '0',
            'comment': str(comment)
        }
        return dumps(payload)


class Stores(Resource):
    """
    Retrieves Store details
    """

    path = 'stores'

    def all(self):
        return self.connection.send_request(method='GET', url=self.url)

    def get(self, id):
        url = self.url + ('/%s' % id)
        return self.connection.send_request(method='GET', url=url)


class Products(Resource):
    """
    Retrieves Product details
    """
    path = 'products'

    def get(self, id):
        url = self.url + ('/%s' % id)
        return self.connection.send_request(method='GET', url=url)
