import logging
from decimal import Decimal
from django.conf import settings
from django.db.models import Q

from measurement.measures import Weight

from core.usps import USPSApi
from core.exceptions import USPSPostageError, ShippingAddressError
from core.models import (
    ShippingRate,
    SiteSettings,
)
from core import (
    ShippingService,
    ShippingProvider,
    ShippingContainer
)

logger = logging.getLogger(__name__)


def get_shipping_container_choices_from_weight(weight):
    is_selectable = Q(
        is_selectable=True
    )
    min_weight_matched = Q(
        min_order_weight__lte=weight) | Q(
        min_order_weight__isnull=True
    )
    max_weight_matched = Q(
        max_order_weight__gte=weight) | Q(
        max_order_weight__isnull=True
    )
    containers = ShippingRate.objects.filter(
        is_selectable & min_weight_matched & max_weight_matched
    )
    return containers


def get_shipping_container_from_choices(choices):
    if len(choices) == 0:
        return SiteSettings.load().default_shipping_rate.container
    return choices[0].container


def get_shipping_cost(total_weight, postal_code):
    if not total_weight > Weight(lb=0):
        return Decimal('0.00')

    container = get_shipping_container_from_choices(
        get_shipping_container_choices_from_weight(total_weight)
    )

    usps_rate_request = build_usps_rate_request(
        str(total_weight.lb), container, str(postal_code)
    )

    usps = USPSApi(SiteSettings.load().usps_user_id, test=settings.DEBUG)

    try:
        validation = usps.get_rate(usps_rate_request)
    except ConnectionError as e:
        raise e(
            'Could not connect to USPS, try again.'
        )

    logger.info(validation.result)
    try:
        postage = dict(
            validation.result['RateV4Response']['Package']['Postage']
        )
    except KeyError:
        raise USPSPostageError(
            'Could not retrieve postage.'
        )

    if usps_rate_request['service'] == ShippingContainer.PRIORITY:
        shipping_cost = Decimal(postage['Rate'])
    elif usps_rate_request['service'] == ShippingContainer.PRIORITY_COMMERCIAL:
        shipping_cost = Decimal(postage['CommercialRate'])

    return shipping_cost


def build_usps_rate_request(weight, container, zip_destination):
    service = ShippingContainer.get_shipping_service_from_container(container)
    return \
        {
            'service': service,
            'zip_origination': SiteSettings.load().default_zip_origination,
            'zip_destination': zip_destination,
            'pounds': weight,
            'ounces': '0',
            'container': container,
            'width': '',
            'length': '',
            'height': '',
            'girth': '',
            'machinable': 'TRUE'
        }
