import unittest
import unittest.mock

from django.conf import settings
from django.template.exceptions import TemplateDoesNotExist
from django.urls import reverse

from oscar.core.loading import get_model

from ocyan.core.fender import config

from ocyan.plugin.oscar.settings import SHOP_BASE_URL

from .utils import OscarSmokeTest

OCYAN_FREE_SHIPPING_CONFIG = {
    "shipping": {"enable_free_shipping": True},
    "cookie_jar": {
        "functional": True,
        "analytical": False,
        "social": False,
        "marketing": False,
    },
}


class OscarPasswordResetTest(OscarSmokeTest):
    def test_reset_password(self):
        response = self.client.get("/%s/password-reset/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)
        url = response.request["PATH_INFO"]
        response = self.client.post(url, {"email": "admin@admin.admin"}, follow=False)
        self.assertEqual(response.status_code, 302)

        response = self.client.get(
            "/%s/password-reset/done/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)

    def test_confirm_password_reset(self):
        response = self.client.get(
            "/%s/password-reset/confirm/MQ/59d-0e26115ab2e49a072ff7/" % SHOP_BASE_URL,
            follow=True,
        )
        self.assertEqual(response.status_code, 200)

        response = self.client.get(
            "/%s/password-reset/done/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)


class OscarCatalogueUrlTest(OscarSmokeTest):
    def test_catalogue_root(self):
        "The catalogue root that shows all products should work"
        # make sure at least 1 product is in the search index
        # (fixtures do not trigger index update)
        Product = get_model("catalogue", "Product")
        a = Product(upc="koe", slug="koe", product_class_id=1)
        a.save()
        response = self.client.get("/%s/catalogue/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)

    def test_catalogue_product(self):
        "The product detail views should work"
        response = self.client.get(
            "/%s/catalogue/dikke-shit-ouwe_2/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Hermes Bikini")
        response = self.client.get("/%s/catalogue/henk_3/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Hubble Photo")
        response = self.client.get(
            "/%s/catalogue/serious-product_4/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "serious product")
        response = self.client.get(
            "/%s/catalogue/second_5/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "second")

    def test_catalogue_parent_product(self):
        "The product detail view for parent products should work"
        response = self.client.get(
            "/%s/catalogue/oscar-t-shirt_1/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)

    def test_catalogue_product_redirect(self):
        "The product detaild views should automatically redirect to the current location"
        Product = get_model("catalogue", "Product")

        response = self.client.get(
            "/%s/catalogue/does-not-exist_2/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Hermes Bikini")
        self.assertRedirects(
            response, Product.objects.get(pk=2).get_absolute_url(), status_code=301
        )
        response = self.client.get(
            "/%s/catalogue/does-not-exist_3/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Hubble Photo")
        self.assertRedirects(
            response, Product.objects.get(pk=3).get_absolute_url(), status_code=301
        )
        response = self.client.get(
            "/%s/catalogue/does-not-exist_4/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "serious product")
        self.assertRedirects(
            response, Product.objects.get(pk=4).get_absolute_url(), status_code=301
        )
        response = self.client.get(
            "/%s/catalogue/does-not-exist_5/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "second")
        self.assertRedirects(
            response, Product.objects.get(pk=5).get_absolute_url(), status_code=301
        )

    def test_catalogue_category(self):
        "The category page should work"
        Category = get_model("catalogue", "Category")
        category = Category.objects.order_by("id").first()
        category_url = reverse(
            "catalogue:category",
            kwargs={"category_slug": category.full_slug, "pk": category.pk},
        )
        response = self.client.get(category_url, follow=True)
        if response.status_code == 404:
            self.skipTest("Catalogue category route is not enabled in this stack")
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, category.name)

    def test_catalogue_category_redirect(self):
        "The category page should automatically redirect to the current location"
        Category = get_model("catalogue", "Category")
        category = Category.objects.order_by("id").first()
        category_url = reverse(
            "catalogue:category",
            kwargs={"category_slug": category.full_slug, "pk": category.pk},
        )
        response = self.client.get(
            category_url.replace(category.full_slug, "does-not-exist", 1),
            follow=True,
        )
        if response.status_code == 404:
            self.skipTest("Catalogue category route is not enabled in this stack")
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, category.name)
        self.assertRedirects(response, category_url, status_code=301)

    @unittest.skipIf(
        not config.get("oscar", "enable_reviews", False), "reviews are not enabled"
    )
    def test_catalogue_product_review(self):
        "Products review detail view should work"
        ProductReview = get_model("reviews", "ProductReview")
        self.assertEqual(ProductReview.objects.count(), 1)
        response = self.client.get(
            "/%s/catalogue/second_5/reviews/1/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)

    def test_range(self):
        "Range view should work"
        response = self.client.get(
            "/%s/catalogue/ranges/de-range/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)


@unittest.mock.patch.object(config, "settings", OCYAN_FREE_SHIPPING_CONFIG)
class OscarBasketUrlTest(OscarSmokeTest):
    def test_add_to_basket(self):
        "It should be possible to add stuff to the basket"
        body = {"quantity": 1}
        response = self.client.get(
            "/%s/basket/add/2/" % SHOP_BASE_URL, body, follow=True
        )
        url = response.request["PATH_INFO"]
        response = self.client.post(url, body, follow=True)
        self.assertEqual(response.status_code, 200)

    def test_basket(self):
        "It should be possible to view the basket"
        if not settings.SHOW_BASKET_POPUP_MODAL:
            response = self.client.get("/%s/basket/" % SHOP_BASE_URL, follow=True)
            self.assertEqual(response.status_code, 200)
            self.test_add_to_basket()
            response = self.client.get("/%s/basket/" % SHOP_BASE_URL, follow=True)
            self.assertEqual(response.status_code, 200)

    def test_basket_saved(self):
        "It should be possible to view saved baskets"
        response = self.client.get("/%s/basket/saved/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)


@unittest.mock.patch.object(config, "settings", OCYAN_FREE_SHIPPING_CONFIG)
class OscarCheckoutUrlTest(OscarSmokeTest):
    @unittest.skipUnless(
        config.get("oscar", "allow_anon_checkout", False),
        "Can not view checkout page if anonymous checkout is disabled",
    )
    def test_checkout(self):
        "It should be possible to view the checkout page"
        body = {"quantity": 1}
        response = self.client.get(
            "/%s/basket/add/2/" % SHOP_BASE_URL, body, follow=True
        )
        url = response.request["PATH_INFO"]
        response = self.client.post(url, body, follow=True)
        self.assertEqual(response.status_code, 200)

        response = self.client.get("/%s/checkout/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Hermes Bikini")


class OscarAccountsTest(OscarSmokeTest):
    def setUp(self):
        super().setUp()
        self.assertTrue(self.client.login(username="admin", password="admin"))

    def test_account_summary(self):
        response = self.client.get("/%s/accounts/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)

    def test_change_password(self):
        response = self.client.get(
            "/%s/accounts/change-password/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)

    def test_profile(self):
        response = self.client.get("/%s/accounts/profile/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/profile/edit/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/profile/delete/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)

    def test_orders(self):
        response = self.client.get("/%s/accounts/orders/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/orders/100099/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)

    def test_orders_broken_urls(self):
        "If these tests fail, that means they FIXED something!!!"
        with self.assertRaises(TemplateDoesNotExist):
            self.client.get("/%s/accounts/orders/100099/1" % SHOP_BASE_URL, follow=True)

    def test_address(self):
        response = self.client.get(
            "/%s/accounts/addresses/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/addresses/add/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/addresses/1/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/addresses/1/delete/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/addresses/1/default_for_billing/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/addresses/1/default_for_shipping/" % SHOP_BASE_URL,
            follow=True,
        )
        self.assertEqual(response.status_code, 200)

    def test_emails(self):
        response = self.client.get("/%s/accounts/emails/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)

    def test_notifications(self):
        response = self.client.get(
            "/%s/accounts/notifications/inbox/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/notifications/archive/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/notifications/update/" % SHOP_BASE_URL, follow=True
        )
        self.assertIn(response.status_code, [410, 405])

    def test_alerts(self):
        response = self.client.get("/%s/accounts/alerts/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)

    @unittest.skipIf(
        not config.get("oscar", "enable_wishlist", False), "reviews are not enabled"
    )
    def test_wishlists(self):
        response = self.client.get(
            "/%s/accounts/wishlists/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/wishlists/add/2/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/wishlists/create/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/accounts/wishlists/create/with-product/2/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)


class OscarLoginTest(OscarSmokeTest):
    def test_login_url(self):
        "The login url should be properly configured"
        response = self.client.get(settings.LOGIN_URL, follow=False)
        self.assertEqual(
            response.status_code, 200, "settings.LOGIN_URL should not cause a redirect"
        )
        response = self.client.get("/%s/accounts/login/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(
            response.status_code, 200, "The old login url should still work"
        )


class OscarDashboardTest(OscarSmokeTest):
    def test_must_login(self):
        response = self.client.get("/%s/dashboard/" % SHOP_BASE_URL, follow=False)
        self.assertNotEqual(response.status_code, 200)
        self.client.login(username="admin", password="admin")
        response = self.client.get(reverse("dashboard:index"), follow=False)
        self.assertEqual(response.status_code, 200)

    def test_one_more_random_url(self):
        response = self.client.get(
            "/%s/dashboard/orders/" % SHOP_BASE_URL, follow=False
        )
        self.assertNotEqual(response.status_code, 200)
        self.client.login(username="admin", password="admin")
        response = self.client.get(reverse("dashboard:order-list"), follow=False)
        self.assertEqual(response.status_code, 200)

    def test_bullshit_url(self):
        self.client.login(username="admin", password="admin")
        response = self.client.get(
            "/%s/dashboard/kakapoep/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 404)


class OscarOfferTest(OscarSmokeTest):
    def test_offer_listing(self):
        response = self.client.get("/%s/offers/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, "Offer for coupon 'kut'")
        self.assertContains(response, "korting")
        self.assertContains(response, "Vast korting bedrag")

    def test_offer_detail(self):
        response = self.client.get(
            "/%s/offers/offer-for-coupon-kut/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.get("/%s/offers/korting/" % SHOP_BASE_URL, follow=True)
        self.assertEqual(response.status_code, 200)
        response = self.client.get(
            "/%s/offers/vast-korting-bedrag/" % SHOP_BASE_URL, follow=True
        )
        self.assertEqual(response.status_code, 200)
