from oscar.apps.shipping.methods import FixedPrice
from decimal import Decimal
from apps.shipping.abstract_shipping import AbstractShipping
from django.conf import settings
import requests
from django.utils import timezone
from datetime import timedelta
from apps.shipping import settings as ship_settings
import logging
import simplejson as json
import io
from apps.shipping.exceptions import ShippingApiError
from django.utils.text import mark_safe

logger = logging.getLogger('shipping')


class HonestBee(FixedPrice, AbstractShipping):
    name = 'Express shipping'
    code = 'honestbee'
    charge_excl_tax = Decimal('2.50')
    charge_incl_tax = Decimal('2.50')
    description = 'Delivery within 3 working days. Track online'

    # Honest bee stuff
    api_key = getattr(settings, 'HONESTBEE_API_KEY')
    base_endpoint = getattr(settings, 'HONESTBEE_ENDPOINT')
    endpoint = base_endpoint + "{ep}?access_token=" + api_key
    CURRENCY_CODE = 'SGD'

    def _get_pickup_date(self):
        return timezone.now() + timedelta(days=1)

    def _get_pickup_contact(self, order):
        return {
            "email": ship_settings.SENDER_EMAIL,
            "first_name": ship_settings.SENDER_FIRST_NAME,
            "last_name": ship_settings.SENDER_LAST_NAME,
            "contact_number": ship_settings.SENDER_CONTACT_NUMBER,
            "alt_contact_number": ship_settings.SENDER_CONTACT_NUMBER_ALT
        }

    def _get_pickup_address(self, order):
        return {
            "street1": ship_settings.SENDER_STREET_1,
            "street2": ship_settings.SENDER_STREET_2,
            "unit": ship_settings.SENDER_UNIT_NUMBER,
            "floor": ship_settings.SENDER_FLOOR_NUMBER,
            "postal_code": ship_settings.SENDER_POSTAL_CODE,
            "city": ship_settings.SENDER_CITY,
            "state": ship_settings.SENDER_STATE,
            "country_code": ship_settings.SENDER_COUNTRY_CODE,
            "type": ship_settings.SENDER_TYPE
        }

    def _get_customer_contact(self, order):
        return {
            "email": order.user.email,
            "first_name": order.shipping_address.first_name,
            "last_name": order.shipping_address.last_name,
            "contact_number": str(order.shipping_address.phone_number),
            "state": "singapore",
            "city": "singapore",
        }

    def _get_customer_address(self, order):
        return {
            "street1": order.shipping_address.line1,
            "street2": order.shipping_address.line2,
            "postal_code": order.shipping_address.postcode,
            "city": "Singapore",
            "state": "singapore",
            "country_code": "SG",
        }

    def process_shipment(self, order):
        """
        Process the shipment for given order.
        :param order:
        :return:
        """
        data = {
            "orders": [
                {
                    "reference": str(order.number),
                    "service_level_code": "3DA",  # 3 day anytime.
                    "pickup": {
                        "contact": self._get_pickup_contact(order),
                        "address": self._get_pickup_address(order),
                        "start_date": self._get_pickup_date().strftime("%Y-%m-%d"),
                        "end_date": self._get_pickup_date().strftime("%Y-%m-%d")
                    },
                    "delivery": {
                        "customer": self._get_customer_contact(order),
                        "address": self._get_customer_address(order),
                    },
                    "packages": [
                        {
                            "width": 0.33,
                            "length": 0.33,
                            "height": 0.14,
                            "weight": float(order.get_total_weight() / 1000),
                            "description": "Coffee Bags/Pods",
                            "package_type": "small",
                            "commodity_type": "food",
                            "commercial_value": {
                                "amount": float(order.basket_total_excl_tax),
                                "currency_code": self.CURRENCY_CODE
                            }
                        }
                    ]
                }
            ]
        }

        res = requests.post(self.endpoint.format(ep="orders"), data=json.dumps(data),
                            headers={'content-type': 'application/json'})
        logger.debug('Honest bee response status code : {}'.format(res.status_code))
        if res.status_code == 201:
            shipment_details = json.loads(res.text)
            tracking_id = shipment_details['order_requests'][0]['tracking_id']
            return tracking_id
        else:
            logger.error('HonestBee returned an error : {} '.format(res.text))
            raise ShippingApiError(res.text)

    def get_waybill_pdf(self, waybill, order=None):
        """
        Get the waybill PDF for honestbee
        :param waybill:
        :param order:
        :return:
        """
        res = requests.get(self.endpoint.format(ep='waybill'), params={'tracking_ids': waybill})
        if res.status_code == 200:
            return io.BytesIO(res.content).getvalue()

    def tracking_url(self):
        url = '<a class="text-info" href="https://www.honestbee.sg/en/goodship/track" target="_blank">Track your shipment</a>'
        return mark_safe(url)

    def tracking_available(self):
        return True


__shipping_method_class__ = HonestBee
