from django.test import TestCase

from shop.models import HULL, Shop, ShopSource
from shop.sources import owner_corporations, source_assets, source_qty
from shop.tests._corptools import make_corp_asset, make_corp_division, make_corp_owner

DIVISION = -600037601
OFFICE = 700000001  # office folder item_id (assets' location_id in a division)
CONTAINER = 900000001


class CorpSourceAssetsTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()
        self.shop = Shop.objects.create(
            slug="c",
            name="C",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
        )
        self.division = make_corp_division(self.corp, location_id=DIVISION)

    def _src(self, container_item_id=None):
        return ShopSource.objects.create(
            shop=self.shop,
            section=HULL,
            corporation_audit=self.corp,
            location_id=DIVISION,
            container_item_id=container_item_id,
        )

    def test_division_source_returns_division_assets(self):
        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=1,
            location_id=OFFICE,
            division_location_id=DIVISION,
        )
        # asset inside a container in the same division: no division FK
        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=2,
            location_id=CONTAINER,
            location_flag="Unlocked",
        )
        src = self._src()
        ids = set(source_assets(src).values_list("item_id", flat=True))
        self.assertEqual(ids, {1})

    def test_container_source_returns_container_contents(self):
        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=2,
            location_id=CONTAINER,
            location_flag="Unlocked",
        )
        src = self._src(container_item_id=CONTAINER)
        ids = set(source_assets(src).values_list("item_id", flat=True))
        self.assertEqual(ids, {2})

    def test_source_qty_sums_quantity_by_type(self):
        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=1,
            location_id=OFFICE,
            division_location_id=DIVISION,
            quantity=3,
        )
        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=5,
            location_id=OFFICE,
            division_location_id=DIVISION,
            quantity=2,
        )

        class T:
            id = 671

        src = self._src()
        self.assertEqual(source_qty(src, T), 5)

    def test_owner_corporations_returns_visible_corp(self):
        self.assertIn(
            self.corp.pk,
            list(owner_corporations(self.user).values_list("pk", flat=True)),
        )


from shop.sources import container_name_for, source_tree  # noqa: E402


class CorpSourceTreeTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()
        self.shop = Shop.objects.create(
            slug="ct",
            name="CT",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
        )
        self.division = make_corp_division(
            self.corp, location_id=DIVISION, name="Jita IV > Fleet Hangar"
        )

    def test_tree_lists_division_and_container(self):
        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=1,
            location_id=OFFICE,
            division_location_id=DIVISION,
        )
        make_corp_asset(
            self.corp,
            type_id=11488,
            item_id=CONTAINER,
            location_id=OFFICE,
            division_location_id=DIVISION,
            singleton=True,
            name="Loot Box",
        )
        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=2,
            location_id=CONTAINER,
            location_flag="Unlocked",
        )
        tree = source_tree(self.user, self.shop)
        self.assertEqual(len(tree), 1)
        node = tree[0]
        self.assertEqual(node["owner_id"], self.corp.pk)
        self.assertEqual(node["owner_name"], self.corp.corporation.corporation_name)
        division = node["locations"][0]
        self.assertEqual(division["location_id"], DIVISION)
        self.assertEqual(division["name"], "Jita IV > Fleet Hangar")
        self.assertEqual(
            division["containers"], [{"item_id": CONTAINER, "name": "Loot Box"}]
        )

    def test_tree_excludes_invisible_corp(self):
        _other_user, _other_corp = make_corp_owner(
            username="c2", char_id=1202, corp_id=2002
        )
        make_corp_division(_other_corp, location_id=-600037602)
        make_corp_asset(
            _other_corp,
            type_id=671,
            item_id=9,
            location_id=OFFICE + 1,
            division_location_id=-600037602,
        )
        tree = source_tree(self.user, self.shop)  # our user, not other
        owner_ids = [n["owner_id"] for n in tree]
        self.assertNotIn(_other_corp.pk, owner_ids)

    def test_tree_excludes_positive_id_managed_locations(self):
        # corptools also registers singleton ships/containers in office folders as
        # managed EveLocations keyed on their POSITIVE item_id (named
        # "Station > Hangar > Type"). Those are not hangar divisions and must not
        # appear in the division list — only negative synthetic division ids do.
        make_corp_division(
            self.corp, location_id=987654321, name="Jita IV > Hangar > Erebus"
        )
        tree = source_tree(self.user, self.shop)
        location_ids = [loc["location_id"] for loc in tree[0]["locations"]]
        self.assertIn(DIVISION, location_ids)
        self.assertNotIn(987654321, location_ids)

    def test_container_name_for_corp(self):
        make_corp_asset(
            self.corp,
            type_id=11488,
            item_id=CONTAINER,
            location_id=OFFICE,
            division_location_id=DIVISION,
            singleton=True,
            name="Loot Box",
        )
        self.assertEqual(
            container_name_for(self.corp.pk, CONTAINER, is_corp=True), "Loot Box"
        )


from unittest.mock import patch  # noqa: E402

from shop.forms import AddStockroomForm  # noqa: E402


class CorpStockroomFormTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()
        self.shop = Shop.objects.create(
            slug="cf",
            name="CF",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
        )
        make_corp_division(self.corp, location_id=DIVISION)

    def test_valid_corp_division_passes(self):
        form = AddStockroomForm(
            {
                "owner_id": self.corp.pk,
                "location_id": DIVISION,
                "container_item_id": "",
            },
            owner=self.user,
            shop=self.shop,
        )
        self.assertTrue(form.is_valid(), form.errors)

    def test_invisible_corp_rejected(self):
        _u, other = make_corp_owner(username="c3", char_id=1303, corp_id=2003)
        make_corp_division(other, location_id=-600037603)
        form = AddStockroomForm(
            {"owner_id": other.pk, "location_id": -600037603, "container_item_id": ""},
            owner=self.user,  # our user cannot see `other`
            shop=self.shop,
        )
        self.assertFalse(form.is_valid())
        self.assertIn("owner_id", form.errors)

    def test_division_not_belonging_to_corp_rejected(self):
        form = AddStockroomForm(
            {"owner_id": self.corp.pk, "location_id": -999999, "container_item_id": ""},
            owner=self.user,
            shop=self.shop,
        )
        self.assertFalse(form.is_valid())


class CorpRefreshTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()
        self.shop = Shop.objects.create(
            slug="cr",
            name="CR",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
        )
        make_corp_division(self.corp, location_id=DIVISION)
        from shop.tests._corptools import make_ship_type

        make_ship_type(type_id=671)  # EveType the HullListing FK-references

    def test_refresh_enqueues_corp_asset_update(self):
        from shop.models import AUTO_STOCK, HullListing
        from shop.sections.hulls.handler import HullSectionHandler

        ShopSource.objects.create(
            shop=self.shop,
            section=HULL,
            corporation_audit=self.corp,
            location_id=DIVISION,
        )
        HullListing.objects.create(
            shop=self.shop, eve_type_id=671, stock_mode=AUTO_STOCK
        )
        with patch("corptools.tasks.corporation.update_corp_assets.apply_async") as m:
            HullSectionHandler().enqueue_source_refresh()
        self.assertTrue(m.called)
        called_corp_ids = [c.kwargs["args"][0] for c in m.call_args_list]
        self.assertIn(self.corp.corporation.corporation_id, called_corp_ids)


from django.urls import reverse  # noqa: E402

from shop.tests._corptools import make_ship_sde_type, make_ship_type  # noqa: E402


class CorpHullPipelineTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()
        from allianceauth.tests.auth_utils import AuthUtils

        AuthUtils.add_permission_to_user_by_name("shop.basic_access", self.user)
        AuthUtils.add_permission_to_user_by_name(
            "shop.manage_corporation_shops", self.user
        )
        from django.contrib.auth.models import User

        self.user = User.objects.get(pk=self.user.pk)
        self.shop = Shop.objects.create(
            slug="cp",
            name="CP",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
            corporation=self.corp.corporation,
        )
        self.shop.enabled_sections = [HULL]
        self.shop.save()
        make_corp_division(self.corp, location_id=DIVISION)
        make_ship_sde_type(type_id=671)
        make_ship_type(type_id=671)

    def test_add_corp_stockroom_autolists_and_computes_stock(self):
        from shop.models import HullListing

        make_corp_asset(
            self.corp,
            type_id=671,
            item_id=1,
            location_id=OFFICE,
            division_location_id=DIVISION,
            quantity=4,
        )
        self.client.force_login(self.user)
        resp = self.client.post(
            reverse("backoffice:add_stockroom", args=[self.shop.pk, "hulls"]),
            {
                "owner_id": self.corp.pk,
                "location_id": DIVISION,
                "container_item_id": "",
                "price_mode": "fixed",
            },
            SERVER_NAME="localhost",
        )
        self.assertRedirects(
            resp, reverse("backoffice:manage_section", args=[self.shop.pk, "hulls"])
        )
        source = self.shop.sources.get(section=HULL)
        self.assertEqual(source.corporation_audit_id, self.corp.pk)
        self.assertIsNone(source.character_audit_id)
        listing = HullListing.objects.get(shop=self.shop, eve_type_id=671)
        self.assertEqual(listing.stock, 4)
