from corptools.models import EveLocation
from django.db import connection
from django.test import TestCase
from django.test.utils import CaptureQueriesContext

from shop.models import HULL, Shop, ShopSource
from shop.sources import source_assets, source_qty, source_tree
from shop.tests._corptools import make_asset, make_owner_character

STATION = 60003760
CONTAINER = 900000001


class SourceAssetsTests(TestCase):
    def setUp(self):
        self.user, self.audit = make_owner_character()
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)

    def _src(self, container_item_id=None):
        return ShopSource.objects.create(
            shop=self.shop,
            section=HULL,
            character_audit=self.audit,
            location_id=STATION,
            container_item_id=container_item_id,
        )

    def test_hangar_source_returns_top_level_hangar_assets(self):
        make_asset(self.audit, type_id=671, item_id=1, location_id=STATION)
        make_asset(self.audit, type_id=671, item_id=2, location_id=CONTAINER)
        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_asset(
            self.audit,
            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_asset(self.audit, type_id=671, item_id=1, location_id=STATION, quantity=3)
        make_asset(self.audit, type_id=671, item_id=2, location_id=STATION, quantity=4)
        make_asset(self.audit, type_id=999, item_id=3, location_id=STATION, quantity=9)

        class FakeType:
            id = 671

        self.assertEqual(source_qty(self._src(), FakeType()), 7)


class CharacterSourceTreeTests(TestCase):
    """The character stockroom tree must resolve station names in a bounded number
    of queries — not one per hangar asset (a linear-scan N+1 that made the manage
    page take ~57s for characters with many hangar stacks)."""

    def _build_char(self, username, char_id, n_hangar_assets):
        user, audit = make_owner_character(username=username, char_id=char_id)
        EveLocation.objects.get_or_create(
            location_id=STATION, defaults={"location_name": "Jita IV-4"}
        )
        for i in range(n_hangar_assets):
            make_asset(
                audit,
                type_id=671,
                item_id=char_id * 100000 + i,
                location_id=STATION,
            )
        shop = Shop.objects.create(slug=f"s{char_id}", name="S", created_by=user)
        return user, shop

    def test_station_name_resolved_from_evelocation(self):
        user, shop = self._build_char("u", 3001, 2)
        tree = source_tree(user, shop)
        self.assertEqual(len(tree), 1)
        self.assertEqual(tree[0]["locations"][0]["name"], "Jita IV-4")

    def test_query_count_independent_of_hangar_asset_count(self):
        u_few, s_few = self._build_char("few", 3002, 3)
        with CaptureQueriesContext(connection) as few:
            source_tree(u_few, s_few)

        u_many, s_many = self._build_char("many", 3003, 30)
        with CaptureQueriesContext(connection) as many:
            source_tree(u_many, s_many)

        self.assertEqual(
            len(many.captured_queries),
            len(few.captured_queries),
            "source_tree query count scales with hangar-asset count "
            f"({len(few.captured_queries)} for 3 assets vs "
            f"{len(many.captured_queries)} for 30) — station-name N+1",
        )
