from billing import Integration, IntegrationNotConfigured
from billing.models import GCNewOrderNotification
from django.conf import settings
from xml.dom import minidom
import hmac
import hashlib
import base64
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.http import HttpResponse, QueryDict
from billing import signals
from django.conf.urls import patterns
from django.utils.decorators import method_decorator
from django.core.exceptions import PermissionDenied

SANDBOX_URL = 'https://sandbox.google.com/checkout/api/checkout/v2/checkout/Merchant/%s'
PROD_URL = 'https://checkout.google.com/api/checkout/v2/checkout/Merchant/%s'

BUTTON_SANDBOX_URL = 'https://sandbox.google.com/checkout/buttons/checkout.gif?merchant_id=%(merchant_id)s&w=%(width)s&h=%(height)s&style=white&variant=text&loc=en_US'
BUTTON_URL = 'https://checkout.google.com/buttons/checkout.gif?merchant_id=%(merchant_id)s&w=%(width)s&h=%(height)s&style=white&variant=text&loc=en_US'

csrf_exempt_m = method_decorator(csrf_exempt)
require_POST_m = method_decorator(require_POST)


class GoogleCheckoutIntegration(Integration):
    display_name = 'Google Checkout'
    template = "billing/google_checkout.html"

    def __init__(self, options=None):
        if not options:
            options = {}
        super(GoogleCheckoutIntegration, self).__init__(options=options)
        merchant_settings = getattr(settings, "MERCHANT_SETTINGS")
        if not merchant_settings or not merchant_settings.get("google_checkout"):
            raise IntegrationNotConfigured("The '%s' integration is not correctly "
                                       "configured." % self.display_name)
        google_checkout_settings = merchant_settings["google_checkout"]
        self.merchant_id = google_checkout_settings['MERCHANT_ID']
        self.merchant_key = google_checkout_settings['MERCHANT_KEY']
        self._signature = None

    @property
    def service_url(self):
        if self.test_mode:
            return SANDBOX_URL % self.merchant_id
        return PROD_URL % self.merchant_id

    def button_image_url(self):
        params = {"merchant_id": self.merchant_id,
                  "width": self.button_width,
                  "height": self.button_height}
        if self.test_mode:
            return BUTTON_SANDBOX_URL % params
        return BUTTON_URL % params

    @property
    def button_width(self):
        return self.fields.get("button_width", 180)

    @property
    def button_height(self):
        return self.fields.get("button_height", 46)

    def _add_nodes(self, doc, parent_node, child_node_name,
                   child_subnode_name, child_node_values):
        """ Helper method that makes it easy to add a bunch of like child nodes
        to a parent node"""
        if child_node_values:
            for value in child_node_values:
                child_node = doc.createElement(unicode(child_node_name))
                child_sub_node = doc.createElement(unicode(child_subnode_name))
                child_node.appendChild(child_sub_node)
                child_sub_node.appendChild(doc.createTextNode(value))
                parent_node.appendChild(child_node)

    def _shipping_allowed_excluded(self, doc, parent_node, data):
        """ Build the nodes for the allowed-areas, excluded-areas
        for shipping-restrictions and address-filters """
        if not data:
            return
        states = data.get('us-state-area', None)
        zips = data.get('us-zip-area', None)
        country = data.get('us-country-area', None)
        world = data.get('world-area', False)
        postal = data.get('postal-area', None)

        self._add_nodes(doc, parent_node, 'us-state-area', 'state', states)
        self._add_nodes(doc, parent_node, 'us-zip-area', 'zip-pattern', zips)

        if country:
            us_country_area = doc.createElement('us-country-area')
            us_country_area.setAttribute('country-area', unicode(country))
            parent_node.appendChild(us_country_area)

        if world:
            parent_node.appendChild(doc.createElement('world-area'))

        if postal:
            for post in postal:
                p_country_code = post.get('country-code', None)
                p_pattern = post.get('postal-code-pattern', None)
                postal_area = doc.createElement('postal-area')
                if p_country_code:
                    c_code = doc.createElement('country-code')
                    c_code.appendChild(doc.createTextNode(unicode(p_country_code)))
                    postal_area.appendChild(c_code)
                if p_pattern:
                    for pp in p_pattern:
                        p_p = doc.createElement('postal-code-pattern')
                        p_p.appendChild(doc.createTextNode(unicode(pp)))
                        postal_area.appendChild(p_p)
                parent_node.appendChild(postal_area)


    def _shipping_restrictions_filters(self, doc, parent_node, data):
        """ process the shipping restriction and address-filter sections for
        the shipping method merchant-calculated-shipping and flat-rate-shipping
        """
        the_allowed_areas = data.get('allowed-areas', None)
        the_excluded_areas = data.get('excluded-areas', None)
        allow_us_po_box = data.get('allow-us-po-box', None)

        if allow_us_po_box is not None:
            allow_po_box = doc.createElement('allow-us-po-box')
            allow_po_box.appendChild(
                    doc.createTextNode(str(allow_us_po_box).lower()))
            parent_node.appendChild(allow_po_box)

        if the_allowed_areas:
            allowed_areas = doc.createElement('allowed-areas')
            parent_node.appendChild(allowed_areas)
            self._shipping_allowed_excluded(doc,
                                            allowed_areas,
                                            the_allowed_areas)

        if the_excluded_areas:
            excluded_areas = doc.createElement('excluded-areas')
            parent_node.appendChild(excluded_areas)
            self._shipping_allowed_excluded(doc,
                                            excluded_areas,
                                            the_excluded_areas)


    def _process_tax_rule(self, doc, parent_node, node_name, data, show_shipping_tax=True):
        """ process a tax rule default_tax_rule, and alternative_tax_rule"""
        tax_rule = doc.createElement(node_name)
        parent_node.appendChild(tax_rule)
        shipping_taxed = data.get('shipping-taxed', False)
        rate = data.get('rate', 0)
        tax_area = data.get('tax-area', {})
        zips = tax_area.get('us-zip-area', [])
        states = tax_area.get('us-state-area', [])
        postal = tax_area.get('postal-area', [])
        country = tax_area.get('us-country-area', None)
        word_area = tax_area.get('world-area', False)

        if shipping_taxed is not None and show_shipping_tax:
            shippingtaxed_node = doc.createElement('shipping-taxed')
            shippingtaxed_node.appendChild(
            doc.createTextNode(str(shipping_taxed).lower()))
            tax_rule.appendChild(shippingtaxed_node)

        rate_node = doc.createElement('rate')
        rate_node.appendChild(
        doc.createTextNode(str(rate)))
        tax_rule.appendChild(rate_node)

        # if there is more then one area then the tag switches from
        # tax-area to tax-areas.
        total_areas = len(zips) + len(states) + len(postal)
        if word_area:
            total_areas += 1
        if country is not None:
            total_areas += 1

        if total_areas == 1:
            tax_area_label = 'tax-area'
        else:
            tax_area_label = 'tax-areas'

        tax_area_node = doc.createElement(tax_area_label)
        tax_rule.appendChild(tax_area_node)

        self._add_nodes(doc, tax_area_node, 'us-state-area', 'state', states)
        self._add_nodes(doc, tax_area_node, 'us-zip-area', 'zip-pattern', zips)

        if country is not None:
            us_country_area = doc.createElement('us-country-area')
            us_country_area.setAttribute('country-area', unicode(country))
            tax_area_node.appendChild(us_country_area)

        if word_area:
            tax_area_node.appendChild(doc.createElement('world-area'))

        if postal:
            for post in postal:
                p_country_code = post.get('country-code', None)
                p_pattern = post.get('postal-code-pattern', None)
                postal_area = doc.createElement('postal-area')
                if p_country_code:
                    c_code = doc.createElement('country-code')