"""Corp blueprint mirror + token tests (ESI fetch is mocked/not needed)."""

from django.test import TestCase

from shop.models import CorporationBlueprint
from shop.sections.bpc.blueprints import corp_blueprint_token, store_corp_blueprints
from shop.tests._corptools import make_corp_owner


class StoreCorpBlueprintsTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()

    def _row(self, item_id, me=10, te=20, runs=50, type_id=12040, quantity=-2):
        return {
            "item_id": item_id,
            "type_id": type_id,
            "material_efficiency": me,
            "time_efficiency": te,
            "runs": runs,
            "quantity": quantity,
        }

    def test_upsert_creates_and_updates(self):
        store_corp_blueprints(
            self.corp, [self._row(1), self._row(2, me=0, te=0, runs=1)]
        )
        self.assertEqual(CorporationBlueprint.objects.count(), 2)
        bp = CorporationBlueprint.objects.get(item_id=1)
        self.assertEqual((bp.me, bp.te, bp.runs), (10, 20, 50))
        store_corp_blueprints(self.corp, [self._row(1, me=5)])
        bp.refresh_from_db()
        self.assertEqual(bp.me, 5)

    def test_stale_rows_pruned(self):
        store_corp_blueprints(self.corp, [self._row(1), self._row(2)])
        store_corp_blueprints(self.corp, [self._row(1)])
        self.assertEqual(
            set(CorporationBlueprint.objects.values_list("item_id", flat=True)), {1}
        )


class CorpBlueprintTokenTests(TestCase):
    def test_no_director_token_returns_none(self):
        # make_corp_owner makes the char a director but adds NO esi.Token, so there
        # is no scoped token available -> None (exercises the CharacterRoles query).
        _user, corp = make_corp_owner()
        self.assertIsNone(corp_blueprint_token(corp))


class FetchCorpBlueprintsErrorTests(TestCase):
    def test_esi_failure_degrades_to_empty(self):
        from unittest.mock import patch

        from shop.sections.bpc import blueprints

        _user, corp = make_corp_owner()
        with (
            patch.object(blueprints, "corp_blueprint_token", return_value=object()),
            patch.object(blueprints, "_esi") as esi,
        ):
            op = getattr(
                esi.return_value.client.Corporation,
                "GetCorporationsCorporationIdBlueprints",
            )
            op.return_value.results.side_effect = RuntimeError("ESI 403")
            self.assertEqual(blueprints.fetch_corp_blueprints(corp), [])


from shop.models import BPC, BpcVariant, Shop, ShopSource  # noqa: E402
from shop.sections.bpc.stock import recompute_bpc_stock  # noqa: E402
from shop.tests._corptools import (  # noqa: E402
    make_corp_asset,
    make_corp_blueprint,
    make_corp_division,
    make_ship_type,
)

DIVISION = -600037601
OFFICE = 700000001


class CorpBpcRecomputeTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()
        self.bp_type = make_ship_type(type_id=12040, name="Rifter Blueprint")
        self.shop = Shop.objects.create(
            slug="cb",
            name="CB",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
        )
        make_corp_division(self.corp, location_id=DIVISION)
        ShopSource.objects.create(
            shop=self.shop,
            section=BPC,
            corporation_audit=self.corp,
            location_id=DIVISION,
        )

    def _copy(self, item_id, me, te, runs):
        make_corp_asset(
            self.corp,
            type_id=self.bp_type.id,
            item_id=item_id,
            location_id=OFFICE,
            division_location_id=DIVISION,
            blueprint_copy=True,
        )
        make_corp_blueprint(
            self.corp, item_id=item_id, type_id=self.bp_type.id, me=me, te=te, runs=runs
        )

    def test_corp_copies_group_into_variants(self):
        self._copy(1, me=10, te=20, runs=50)
        self._copy(2, me=10, te=20, runs=50)  # same variant -> stock 2
        self._copy(3, me=0, te=0, runs=1)  # different variant
        recompute_bpc_stock(self.shop)
        variants = {
            (v.me, v.te, v.runs): v.stock
            for v in BpcVariant.objects.filter(listing__shop=self.shop)
        }
        self.assertEqual(variants, {(10, 20, 50): 2, (0, 0, 1): 1})

    def test_unresolvable_copy_ignored(self):
        make_corp_asset(
            self.corp,
            type_id=self.bp_type.id,
            item_id=9,
            location_id=OFFICE,
            division_location_id=DIVISION,
            blueprint_copy=True,
        )
        recompute_bpc_stock(self.shop)
        self.assertEqual(BpcVariant.objects.filter(listing__shop=self.shop).count(), 0)


from unittest.mock import patch  # noqa: E402

from shop.sections.bpc.handler import BpcSectionHandler  # noqa: E402


class CorpBpcHandlerTests(TestCase):
    def setUp(self):
        self.user, self.corp = make_corp_owner()
        self.shop = Shop.objects.create(
            slug="ch",
            name="CH",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
        )
        make_corp_division(self.corp, location_id=DIVISION)
        self.source = ShopSource.objects.create(
            shop=self.shop,
            section=BPC,
            corporation_audit=self.corp,
            location_id=DIVISION,
        )

    def test_missing_token_list_uses_owner_display_for_corp(self):
        from django.test import RequestFactory

        req = RequestFactory().get("/")
        req.user = self.user
        with patch("shop.sections.bpc.handler.corp_blueprint_token", return_value=None):
            ctx = BpcSectionHandler().manage_context(self.shop, req)
        self.assertIn(
            self.corp.corporation.corporation_name, ctx["missing_token_owners"]
        )

    def test_stockroom_added_refreshes_corp_mirror(self):
        cd = {}
        with patch("shop.sections.bpc.blueprints.refresh_corporation_blueprints") as m:
            BpcSectionHandler().stockroom_added(self.source, cd)
        m.assert_called_once()
        self.assertEqual(m.call_args.args[0].pk, self.corp.pk)

    def test_enqueue_source_refresh_splits_by_kind(self):
        with patch("shop.tasks.refresh_blueprints_for_corporation.apply_async") as mc:
            returned = BpcSectionHandler().enqueue_source_refresh()
        self.assertTrue(mc.called)
        self.assertIn(self.corp.pk, returned)


from django.urls import reverse  # noqa: E402


class CorpBpcPipelineTests(TestCase):
    def setUp(self):
        from allianceauth.tests.auth_utils import AuthUtils
        from django.contrib.auth.models import User

        self.user, self.corp = make_corp_owner()
        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
        )
        self.user = User.objects.get(pk=self.user.pk)
        self.bp_type = make_ship_type(type_id=12040, name="Rifter Blueprint")
        self.shop = Shop.objects.create(
            slug="cbp",
            name="CBP",
            created_by=self.user,
            shop_type=Shop.ShopType.CORPORATION,
            corporation=self.corp.corporation,
        )
        self.shop.enabled_sections = [BPC]
        self.shop.save()
        make_corp_division(self.corp, location_id=DIVISION)

    def test_add_corp_bpc_stockroom_builds_variants(self):
        make_corp_asset(
            self.corp,
            type_id=self.bp_type.id,
            item_id=1,
            location_id=OFFICE,
            division_location_id=DIVISION,
            blueprint_copy=True,
        )
        make_corp_blueprint(
            self.corp, item_id=1, type_id=self.bp_type.id, me=10, te=20, runs=50
        )
        self.client.force_login(self.user)
        with patch(
            "shop.sections.bpc.blueprints.refresh_corporation_blueprints",
            return_value=0,
        ):
            resp = self.client.post(
                reverse("backoffice:add_stockroom", args=[self.shop.pk, "bpc"]),
                {
                    "owner_id": self.corp.pk,
                    "location_id": DIVISION,
                    "container_item_id": "",
                },
                SERVER_NAME="localhost",
            )
        self.assertRedirects(
            resp, reverse("backoffice:manage_section", args=[self.shop.pk, "bpc"])
        )
        source = self.shop.sources.get(section=BPC)
        self.assertEqual(source.corporation_audit_id, self.corp.pk)
        variant = BpcVariant.objects.get(listing__shop=self.shop)
        self.assertEqual(
            (variant.me, variant.te, variant.runs, variant.stock), (10, 20, 50, 1)
        )
