from decimal import Decimal as D
from unittest import mock

from django.test import TestCase, override_settings
from django.urls import reverse

from oscar.core.loading import get_model

import ocyan.core.fender
from ocyan.core.utils import merge_dicts

Order = get_model("order", "Order")
Basket = get_model("basket", "Basket")

ocyan_settings = ocyan.core.fender.config.settings
CHECKOUT_OCYAN_OPTIONS = merge_dicts(
    ocyan_settings,
    {"shipping": {"enable_charged_shipping": True, "enable_free_shipping": True}},
)


class CheckoutTest(TestCase):
    fixtures = [
        "checkout/auth",
        "checkout/catalogue",
        "checkout/shipping",
        "checkout/paymentmethod",
    ]

    @mock.patch("sorl.thumbnail.templatetags.thumbnail.ThumbnailNodeBase.render")
    @mock.patch.object(ocyan.core.fender.config, "settings", CHECKOUT_OCYAN_OPTIONS)
    def test_login_while_checking_out(self, render):
        "The checkout should work if I log in while checking out."
        render.return_value = ""

        self.assertEqual(Basket.objects.count(), 0, "The basket should be empty")

        basket_add_url = reverse("basket:add", args=(1,))
        body = {"quantity": 3}

        response = self.client.post(basket_add_url, body)
        self.assertEqual(
            response.status_code, 302, "Adding an item to a basket should redirect."
        )

        response = self.client.get(reverse("checkout:index"))
        self.assertEqual(
            response.status_code, 200, "The checkout page should work just fine."
        )

        post_data = {
            "csrfmiddlewaretoken": "",
            "gateway_form-username": "henk@example.com",
            "gateway_form-password": "henk",
            "gateway_form-options": "existing",
            "shipping_address_chooser-address_chooser": "1",
            "shipping_address_form-title": "",
            "shipping_address_form-first_name": "Henk",
            "shipping_address_form-last_name": "Koe",
            "shipping_address_form-line1": "Gatenkaasweg",
            "shipping_address_form-house_number": "4",
            "shipping_address_form-line2": "",
            "shipping_address_form-line3": "",
            "shipping_address_form-line4": "Ergens in Nederlan",
            "shipping_address_form-state": "",
            "shipping_address_form-postcode": "1256AB",
            "shipping_address_form-country": "NL",
            "shipping_address_form-phone_number": "",
            "billing_address_chooser-address_chooser": "5",
            "billing_address_form-email": "viggo@mandelblog.com",
            "billing_address_form-title": "",
            "billing_address_form-first_name": "Viggo",
            "billing_address_form-last_name": "de Vries",
            "billing_address_form-line1": "Weteringdijk",
            "billing_address_form-house_number": "109",
            "billing_address_form-line2": "",
            "billing_address_form-line3": "",
            "billing_address_form-line4": "emst",
            "billing_address_form-state": "",
            "billing_address_form-postcode": "8166KT",
            "billing_address_form-country": "NL",
            "shipping_method_form-method_code": "postnl",
            "payment_method_form-payment_method": "dummy:payment",
            "shipping_address_form-notes": "",
            "accepttermsofservice": "on",
        }

        response = self.client.post(reverse("checkout:index"), post_data)

        self.assertEqual(response.status_code, 302)
        self.assertEqual(
            Order.objects.all().count(),
            0,
            "no order should be made yet because the user just logged in",
        )
        response = self.client.get(reverse("checkout:index"), follow=True)
        self.assertContains(
            response,
            "We have merged 3 items from a previous session to your basket.",
        )

        response = self.client.post(reverse("checkout:index"), post_data)
        self.assertEqual(
            Order.objects.all().count(), 1, "now the order should be created"
        )

        order = Order.objects.first()
        self.assertEqual(order.total_incl_tax, D("305.95"))
        self.assertEqual(order.total_excl_tax, D("252.85"))

    @mock.patch("sorl.thumbnail.templatetags.thumbnail.ThumbnailNodeBase.render")
    @mock.patch.object(ocyan.core.fender.config, "settings", CHECKOUT_OCYAN_OPTIONS)
    @override_settings(ALLOWED_HOSTS=["*"])
    def test_create_account_while_checking_out(self, render):
        "The checkout should work if I create an account in while checking out."
        render.return_value = ""

        self.assertEqual(Basket.objects.count(), 0, "The basket should be empty")

        basket_add_url = reverse("basket:add", args=(1,))
        body = {"quantity": 3}

        response = self.client.post(basket_add_url, body)
        self.assertEqual(
            response.status_code, 302, "Adding an item to a basket should redirect."
        )

        response = self.client.get(reverse("checkout:index"))
        self.assertEqual(
            response.status_code, 200, "The checkout page should work just fine."
        )

        post_data = {
            "csrfmiddlewaretoken": "",
            "gateway_form-username": "rutantutann@example.com",
            "gateway_form-password": "henk_1234",
            "gateway_form-password2": "henk_1234",
            "gateway_form-options": "new",
            "shipping_address_chooser-address_chooser": "1",
            "shipping_address_form-title": "",
            "shipping_address_form-first_name": "Henk",
            "shipping_address_form-last_name": "Koe",
            "shipping_address_form-line1": "Gatenkaasweg",
            "shipping_address_form-house_number": "4",
            "shipping_address_form-line2": "",
            "shipping_address_form-line3": "",
            "shipping_address_form-line4": "Ergens in Nederlan",
            "shipping_address_form-state": "",
            "shipping_address_form-postcode": "1256AB",
            "shipping_address_form-country": "NL",
            "shipping_address_form-phone_number": "",
            "billing_address_chooser-address_chooser": "5",
            "billing_address_form-email": "viggo@mandelblog.com",
            "billing_address_form-title": "",
            "billing_address_form-first_name": "Viggo",
            "billing_address_form-last_name": "de Vries",
            "billing_address_form-line1": "Weteringdijk",
            "billing_address_form-house_number": "109",
            "billing_address_form-line2": "",
            "billing_address_form-line3": "",
            "billing_address_form-line4": "emst",
            "billing_address_form-state": "",
            "billing_address_form-postcode": "8166KT",
            "billing_address_form-country": "NL",
            "shipping_method_form-method_code": "postnl",
            "payment_method_form-payment_method": "dummy:payment",
            "shipping_address_form-notes": "",
            "accepttermsofservice": "on",
        }

        response = self.client.post(reverse("checkout:index"), post_data)

        self.assertEqual(response.status_code, 302)
        self.assertEqual(Order.objects.all().count(), 1, "The order should be created")

        order = Order.objects.first()
        self.assertEqual(order.total_incl_tax, D("305.95"))
        self.assertEqual(order.total_excl_tax, D("252.85"))
