"""Hull pricing / stock-mode model tests."""

from decimal import Decimal

from django.test import TestCase

from shop.models import (
    AUTO_STOCK,
    FIXED_PRICE,
    FIXED_STOCK,
    JITA_BUY_PCT,
    JITA_SELL_PCT,
    HullListing,
    Shop,
)
from shop.tests._corptools import make_asset, make_owner_character, make_ship_type


class HullListingDefaultsTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)

    def test_new_listing_defaults(self):
        listing = HullListing.objects.create(shop=self.shop, eve_type=self.ship)
        self.assertEqual(listing.stock_mode, AUTO_STOCK)
        self.assertEqual(listing.price_mode, FIXED_PRICE)
        self.assertIsNone(listing.price_pct)
        self.assertEqual(listing.price, 0)


class ApplyJitaPriceTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)
        self.listing = HullListing.objects.create(shop=self.shop, eve_type=self.ship)

    def test_pct_of_buy(self):
        self.listing.price_mode = JITA_BUY_PCT
        self.listing.price_pct = Decimal("90")
        changed = self.listing.apply_jita_price(buy=100, sell=200)
        self.assertTrue(changed)
        self.assertEqual(self.listing.price, 90)

    def test_pct_of_sell(self):
        self.listing.price_mode = JITA_SELL_PCT
        self.listing.price_pct = Decimal("50")
        self.listing.apply_jita_price(buy=100, sell=200)
        self.assertEqual(self.listing.price, 100)

    def test_keep_last_known_when_base_none(self):
        self.listing.price_mode = JITA_BUY_PCT
        self.listing.price_pct = Decimal("90")
        self.listing.price = 42
        changed = self.listing.apply_jita_price(buy=None, sell=200)
        self.assertFalse(changed)
        self.assertEqual(self.listing.price, 42)

    def test_fixed_mode_is_noop(self):
        self.listing.price_mode = FIXED_PRICE
        self.listing.price = 5
        changed = self.listing.apply_jita_price(buy=100, sell=200)
        self.assertFalse(changed)
        self.assertEqual(self.listing.price, 5)


class PriceModeDisplayTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)
        self.listing = HullListing.objects.create(shop=self.shop, eve_type=self.ship)

    def test_fixed_zero_is_ask(self):
        self.assertEqual(self.listing.price_mode_display, "Ask")

    def test_fixed_nonzero_is_fixed(self):
        self.listing.price = 5_000_000
        self.assertEqual(self.listing.price_mode_display, "Fixed")

    def test_pct_display(self):
        self.listing.price_mode = JITA_BUY_PCT
        self.listing.price_pct = Decimal("95")
        self.assertEqual(self.listing.price_mode_display, "Jita Buy 95%")

    def test_pct_display_trailing_zeros(self):
        # DecimalField stores 90 as 90.00; must not render as "9E+1".
        self.listing.price_mode = JITA_BUY_PCT
        self.listing.price_pct = Decimal("90.00")
        self.assertEqual(self.listing.price_mode_display, "Jita Buy 90%")


from shop.models import HULL, ShopSource  # noqa: E402


class RecomputeStockSkipsFixedTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.ship = make_ship_type()
        self.station = 60003760
        self.shop = Shop.objects.create(slug="s", name="S", created_by=self.user)
        self.listing = HullListing.objects.create(shop=self.shop, eve_type=self.ship)
        make_asset(
            self.char,
            type_id=self.ship.id,
            item_id=1,
            location_id=self.station,
            quantity=3,
        )
        ShopSource.objects.create(
            shop=self.shop,
            section=HULL,
            character_audit=self.char,
            location_id=self.station,
        )

    def test_auto_recomputes(self):
        self.assertEqual(self.listing.recompute_stock(), 3)

    def test_fixed_is_left_alone(self):
        self.listing.stock_mode = FIXED_STOCK
        self.listing.stock = 7
        self.listing.save()
        self.assertEqual(self.listing.recompute_stock(), 7)


from shop.sections.hulls.forms import EditHullForm  # noqa: E402


class EditHullFormTests(TestCase):
    def _data(self, **over):
        data = {"stock_mode": AUTO_STOCK, "price_mode": FIXED_PRICE, "price": "0"}
        data.update(over)
        return data

    def test_fixed_stock_requires_stock(self):
        form = EditHullForm(self._data(stock_mode=FIXED_STOCK))
        self.assertFalse(form.is_valid())
        self.assertIn("stock", form.errors)

    def test_pct_requires_pct(self):
        form = EditHullForm(self._data(price_mode=JITA_BUY_PCT))
        self.assertFalse(form.is_valid())
        self.assertIn("price_pct", form.errors)

    def test_fixed_price_requires_price(self):
        form = EditHullForm({"stock_mode": AUTO_STOCK, "price_mode": FIXED_PRICE})
        self.assertFalse(form.is_valid())
        self.assertIn("price", form.errors)

    def test_valid_pct(self):
        form = EditHullForm(
            self._data(price_mode=JITA_SELL_PCT, price_pct="90", price="")
        )
        self.assertTrue(form.is_valid(), form.errors)

    def test_persist_flag(self):
        on = EditHullForm(self._data(persist="on"))
        self.assertTrue(on.is_valid(), on.errors)
        self.assertIs(on.cleaned_data["persist"], True)
        off = EditHullForm(self._data())
        self.assertTrue(off.is_valid(), off.errors)
        self.assertIs(off.cleaned_data["persist"], False)


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

    def test_source_price_defaults_to_fixed(self):
        src = ShopSource.objects.create(
            shop=self.shop,
            section=HULL,
            character_audit=self.char,
            location_id=60003760,
        )
        self.assertEqual(src.price_mode, FIXED_PRICE)
        self.assertIsNone(src.price_pct)

    def test_price_rule_display(self):
        src = ShopSource.objects.create(
            shop=self.shop,
            section=HULL,
            character_audit=self.char,
            location_id=60003760,
        )
        self.assertEqual(src.price_rule_display, "Ask")  # fixed default
        src.price_mode = JITA_SELL_PCT
        src.price_pct = Decimal("90.00")
        self.assertEqual(src.price_rule_display, "Jita Sell 90%")


from shop.sections.hulls.forms import AddHullForm, HullStockroomForm  # noqa: E402


class AddHullFormTests(TestCase):
    def test_pct_requires_pct(self):
        form = AddHullForm({"stock_mode": AUTO_STOCK, "price_mode": JITA_BUY_PCT})
        self.assertFalse(form.is_valid())
        self.assertIn("price_pct", form.errors)

    def test_valid_fixed(self):
        ship = make_ship_type()
        form = AddHullForm(
            {
                "eve_type": ship.id,
                "stock_mode": AUTO_STOCK,
                "price_mode": FIXED_PRICE,
                "price": "0",
            }
        )
        self.assertTrue(form.is_valid(), form.errors)


class AddStockroomFormPricingTests(TestCase):
    def _data(self, **over):
        data = {"character_id": "1", "location_id": "2", "price_mode": FIXED_PRICE}
        data.update(over)
        return data

    def test_pct_requires_pct(self):
        form = HullStockroomForm(self._data(price_mode=JITA_SELL_PCT), owner=None)
        form.is_valid()
        self.assertIn("price_pct", form.errors)


from shop.sources import container_name_for  # noqa: E402
from shop.tests._corptools import make_ship_sde_type  # noqa: E402


class ContainerNameForTests(TestCase):
    def setUp(self):
        self.user, self.char = make_owner_character()
        self.station = 60003760
        # eve_sde ItemType named "Giant Secure Container" for the type_name fallback.
        self.ctype = make_ship_sde_type(type_id=11488, category_id=2, group_id=448)
        self.ctype.name = "Giant Secure Container"
        self.ctype.save(update_fields=["name"])

    def _container(self, item_id, name=""):
        return make_asset(
            self.char,
            type_id=self.ctype.id,
            item_id=item_id,
            location_id=self.station,
            quantity=1,
            name=name,
            type_name=self.ctype,
        )

    def test_custom_name(self):
        self._container(500, name="Corp Hangar")
        self.assertEqual(container_name_for(self.char.id, 500), "Corp Hangar")

    def test_falls_back_to_type_name(self):
        self._container(501, name="")
        self.assertEqual(
            container_name_for(self.char.id, 501), "Giant Secure Container"
        )

    def test_none_item_is_blank(self):
        self.assertEqual(container_name_for(self.char.id, None), "")
