"""Order submission view tests."""

import json
from unittest import mock

from django.test import TestCase

from shop.models import Buyer, HullListing, Order, Shop
from shop.tests.test_stock import make_owner_character, make_ship_type
from shop.tests.test_views_storefront import no_manifest_static


@no_manifest_static
class SubmitOrderTests(TestCase):
    def setUp(self):
        self.user, _ = make_owner_character()
        self.shop = Shop.objects.create(
            slug="pub",
            name="Pub",
            created_by=self.user,
            is_published=True,
            enabled_sections=["hulls"],
        )
        self.ship = make_ship_type()
        self.listing = HullListing.objects.create(
            shop=self.shop, eve_type=self.ship, price=1000, stock=5
        )
        self.url = "/shop/pub/order/"

    def _login_buyer(self, cid=90000001, name="Buyer One"):
        s = self.client.session
        s["shop_buyer"] = {"id": cid, "name": name}
        s.save()

    def _post(self, body):
        return self.client.post(
            self.url,
            data=json.dumps(body),
            content_type="application/json",
            SERVER_NAME="localhost",
        )

    def test_requires_buyer_session(self):
        resp = self._post(
            {"lines": [{"listing_id": self.listing.pk, "section": "hulls", "qty": 1}]}
        )
        self.assertEqual(resp.status_code, 403)
        self.assertEqual(Order.objects.count(), 0)

    def test_creates_order_with_server_side_price(self):
        self._login_buyer()
        resp = self._post(
            {
                "lines": [
                    {
                        "listing_id": self.listing.pk,
                        "section": "hulls",
                        "qty": 2,
                        "price": 999999999,
                    }
                ],
                "discord_handle": "buyer1",
                "additional_info": "ME10",
            }
        )
        self.assertEqual(resp.status_code, 200)
        ref = resp.json()["reference"]
        self.assertEqual(len(ref), 5)
        order = Order.objects.get(reference=ref)
        self.assertEqual(order.shop, self.shop)
        self.assertEqual(order.additional_info, "ME10")
        self.assertEqual(order.buyer.discord_handle, "buyer1")
        line = order.lines.get()
        self.assertEqual(line.quantity, 2)
        self.assertEqual(line.unit_price, 1000)  # server price, not client 999999999
        self.assertEqual(line.eve_type, self.ship)

    def test_empty_cart_rejected(self):
        self._login_buyer()
        self.assertEqual(self._post({"lines": []}).status_code, 400)

    def test_listing_from_another_shop_rejected(self):
        self._login_buyer()
        other = Shop.objects.create(
            slug="o",
            name="O",
            created_by=self.user,
            is_published=True,
            enabled_sections=["hulls"],
        )
        foreign = HullListing.objects.create(shop=other, eve_type=self.ship, price=1)
        resp = self._post(
            {"lines": [{"listing_id": foreign.pk, "section": "hulls", "qty": 1}]}
        )
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(Order.objects.count(), 0)

    def test_unknown_section_rejected(self):
        self._login_buyer()
        resp = self._post(
            {"lines": [{"listing_id": self.listing.pk, "section": "modules", "qty": 1}]}
        )
        self.assertEqual(resp.status_code, 400)

    def test_updates_existing_buyer_handle(self):
        self._login_buyer(cid=5, name="Repeat")
        Buyer.objects.create(
            character_id=5, character_name="Repeat", discord_handle="old"
        )
        self._post(
            {
                "lines": [
                    {"listing_id": self.listing.pk, "section": "hulls", "qty": 1}
                ],
                "discord_handle": "new",
            }
        )
        self.assertEqual(Buyer.objects.get(character_id=5).discord_handle, "new")

    def test_bpc_variant_order_captures_label(self):
        from shop.models import BpcListing, BpcVariant

        bshop = Shop.objects.create(
            slug="bp",
            name="BP",
            created_by=self.user,
            is_published=True,
            enabled_sections=["bpc"],
        )
        bp = make_ship_type(type_id=12040, name="Rifter Blueprint")
        listing = BpcListing.objects.create(shop=bshop, eve_type=bp)
        variant = BpcVariant.objects.create(
            listing=listing, me=10, te=20, runs=50, stock=2, price=8_000_000
        )
        self._login_buyer()
        resp = self.client.post(
            "/shop/bp/order/",
            data=json.dumps(
                {"lines": [{"listing_id": variant.pk, "section": "bpc", "qty": 1}]}
            ),
            content_type="application/json",
            SERVER_NAME="localhost",
        )
        self.assertEqual(resp.status_code, 200)
        order = Order.objects.get(reference=resp.json()["reference"])
        line = order.lines.get()
        self.assertEqual(line.section, "bpc")
        self.assertEqual(line.eve_type, bp)
        self.assertEqual(line.unit_price, 8_000_000)
        self.assertIn("ME 10", line.label)

    def test_submit_schedules_notification(self):
        self._login_buyer()
        with mock.patch("shop.views.storefront.notify_new_order") as task:
            with self.captureOnCommitCallbacks(execute=True):
                resp = self._post(
                    {
                        "lines": [
                            {
                                "listing_id": self.listing.pk,
                                "section": "hulls",
                                "qty": 1,
                            }
                        ]
                    }
                )
            self.assertEqual(resp.status_code, 200)
        task.apply_async.assert_called_once()

    def test_storefront_exposes_saved_discord_and_csrf(self):
        Buyer.objects.create(
            character_id=7, character_name="H", discord_handle="myhandle"
        )
        s = self.client.session
        s["shop_buyer"] = {"id": 7, "name": "H"}
        s.save()
        resp = self.client.get("/shop/pub/hulls/", SERVER_NAME="localhost")
        self.assertContains(resp, 'data-buyer-discord="myhandle"')
        self.assertContains(resp, 'name="csrf-token"')
