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

from shop.models import FittedListing, Shop
from shop.tests._corptools import make_owner_character, make_ship_type


class FittedBackofficeTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.user.user_permissions.add(_basic_access_perm())
        self.client = Client()
        self.client.force_login(self.user)
        self.shop = Shop.objects.create(
            slug="s", name="S", created_by=self.user, enabled_sections=["fitted"]
        )
        hull = make_ship_type(type_id=23773, name="Ragnarok")
        self.listing = FittedListing.objects.create(
            shop=self.shop, eve_type=hull, item_id=9001, ship_name="Rag", fit_json={}
        )

    def test_manage_section_renders_fitted_template(self):
        url = reverse("backoffice:manage_section", args=[self.shop.pk, "fitted"])
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, 200)
        self.assertTemplateUsed(resp, "shop/manage_fitted.html")
        self.assertContains(resp, "Rag")

    def test_malicious_container_name_cannot_break_out_of_picker(self):
        from shop.tests._corptools import make_asset

        station = 60003760
        # a corp-mate (or the user) names a container to try to break out of the
        # inline <script> that carries the stockroom picker tree
        make_asset(
            self.char,
            type_id=11488,
            item_id=900001,
            location_id=station,
            name="</script><img src=x onerror=alert(31337)>",
        )
        make_asset(self.char, type_id=671, item_id=900002, location_id=900001)  # child
        url = reverse("backoffice:manage_section", args=[self.shop.pk, "fitted"])
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, 200)
        self.assertContains(resp, "source-tree-data")  # json_script element used
        # json_script escapes < and > -> the payload can't break the <script> block
        self.assertNotContains(resp, "<img src=x onerror")

    def test_order_detail_renders_fit_modal_for_fitted_line(self):
        from shop.models import Buyer, Order, OrderLine

        buyer = Buyer.objects.create(character_id=42, character_name="Buyer")
        order = Order.objects.create(shop=self.shop, buyer=buyer)
        OrderLine.objects.create(
            order=order,
            section="fitted",
            eve_type=self.listing.eve_type,
            quantity=1,
            unit_price=0,
            listing_id=self.listing.pk,
            label="Doomsday",
            fit_json={
                "slots": [
                    {
                        "flag": "HiSlot0",
                        "type_id": 3057,
                        "name": "Big Gun",
                        "charge": None,
                    }
                ],
                "drones": [],
                "cargo": [],
                "manifest": [],
            },
        )
        url = reverse("backoffice:order_detail", args=[self.shop.pk, order.reference])
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, 200)
        self.assertContains(resp, "fitModal")  # the modal exists
        self.assertContains(resp, "Big Gun")  # the fit is rendered
        self.assertContains(resp, "Copy EFT")

    def test_edit_fitted_sets_price(self):
        url = reverse("backoffice:edit_fitted", args=[self.shop.pk, self.listing.pk])
        resp = self.client.post(url, {"price": "90000000000"})
        self.assertEqual(resp.status_code, 302)
        self.listing.refresh_from_db()
        self.assertEqual(self.listing.price, 90_000_000_000)

    def test_edit_fitted_sets_persist_and_description(self):
        url = reverse("backoffice:edit_fitted", args=[self.shop.pk, self.listing.pk])
        resp = self.client.post(
            url,
            {"price": "0", "persist": "on", "description": "Shiny **PvP** rag"},
        )
        self.assertEqual(resp.status_code, 302)
        self.listing.refresh_from_db()
        self.assertTrue(self.listing.persist)
        self.assertEqual(self.listing.description, "Shiny **PvP** rag")

    def test_edit_fitted_unchecked_persist_is_false(self):
        FittedListing.objects.filter(pk=self.listing.pk).update(persist=True)
        url = reverse("backoffice:edit_fitted", args=[self.shop.pk, self.listing.pk])
        self.client.post(url, {"price": "0"})  # persist checkbox absent
        self.listing.refresh_from_db()
        self.assertFalse(self.listing.persist)

    def test_remove_fitted_deletes(self):
        url = reverse("backoffice:remove_fitted", args=[self.shop.pk, self.listing.pk])
        resp = self.client.post(url)
        self.assertEqual(resp.status_code, 302)
        self.assertFalse(FittedListing.objects.filter(pk=self.listing.pk).exists())

    def test_toggle_featured_generic_works_for_fitted(self):
        url = reverse(
            "backoffice:toggle_featured", args=[self.shop.pk, "fitted", self.listing.pk]
        )
        self.client.post(url)
        self.listing.refresh_from_db()
        self.assertTrue(self.listing.featured)


def _basic_access_perm():
    from django.contrib.auth.models import Permission

    return Permission.objects.get(
        codename="basic_access", content_type__app_label="shop"
    )
