"""
Item Crafting Engine for FreeExile.
Implements deep Path of Exile 2 style deterministic and stochastic crafting.
Supports iLvl tier gating, slot exclusivity, pinnacle boss materials,
quest-gated Primal Boneforge trade-off affixes, and Feral Corruption.
"""

from __future__ import annotations
import copy
import random
import uuid
from enum import Enum
from typing import List, Optional, Tuple, Set, Union, Any

from server.world.item_crafting_types import (
    ItemSlot,
    ItemRarity,
    AffixType,
    PrimalCurrencyType,
    DownsidePenaltyType,
    AffixDefinition,
    AffixMod,
    CraftingItem,
    CraftingResult,
)
from server.world.item_affix_catalog import (
    get_available_affixes,
    get_tradeoff_affix_by_id,
    CANONICAL_AFFIX_DEFINITIONS,
    CANONICAL_TRADEOFF_AFFIXES,
)


class SpiritStoneCurrency(Enum):
    KHAI_LINH_CHAU = "KHAI_LINH_CHAU"               # Transmutation Orb
    HON_NGUYEN_THACH = "HON_NGUYEN_THACH"           # Chaos Orb
    THIEN_MENH_DAN = "THIEN_MENH_DAN"               # Exalted Orb
    THAN_TUONG_PHU = "THAN_TUONG_PHU"               # Orb of Annulment
    THAI_HU_CAN_KHON_KINH = "THAI_HU_CAN_KHON_KINH" # Mirror of Kalandra


def calculate_crafting_gold_fee(currency: PrimalCurrencyType, item_level: int) -> int:
    """Calculates exponential crafting gold fee based on currency type and item level."""
    base_fees = {
        PrimalCurrencyType.HAC_THACH_MAI_NHAN: 50,
        PrimalCurrencyType.COT_GIAP_THAO_THIET: 50,
        PrimalCurrencyType.TRO_XUONG_TAY_UE: 100,
        PrimalCurrencyType.BAO_MA_THACH: 150,
        PrimalCurrencyType.HAC_SO_THACH: 200,
        PrimalCurrencyType.UAN_MA_THACH: 300,
        PrimalCurrencyType.CO_COT_AN: 800,
        PrimalCurrencyType.HUYET_HON_THACH: 1500,
        PrimalCurrencyType.U_MINH_COT_DINH: 5000,
        PrimalCurrencyType.COT_DAO_TUOC_DOAT: 3000,
        PrimalCurrencyType.TINH_HOA_HUYET_THACH: 4000,
        PrimalCurrencyType.TA_HUYET_DI_BIEN_THACH: 10000,
        PrimalCurrencyType.HUYET_ANH_CO_KINH: 100000,
    }
    base = base_fees.get(currency, 500)
    ilvl_clamped = max(1, min(100, item_level))
    scale = (1.0 + ilvl_clamped / 25.0) ** 1.6
    return int(round(base * scale))


class ItemCraftingEngine:
    """Server-Authoritative Crafting Engine."""

    def __init__(self, rng_seed: Optional[int] = None) -> None:
        self._rng = random.Random(rng_seed)

    def _roll_affix(
        self,
        slot: ItemSlot,
        affix_type: AffixType,
        item_level: int,
        guaranteed_tier: Optional[int] = None,
    ) -> Optional[AffixMod]:
        """Rolls an affix from catalog based on slot and iLvl gating."""
        pool = get_available_affixes(slot, affix_type, item_level)
        if not pool:
            return None
        if guaranteed_tier is not None:
            tier_pool = [a for a in pool if a.tier == guaranteed_tier]
            if tier_pool:
                pool = tier_pool

        chosen = self._rng.choices(pool, weights=[a.weight for a in pool], k=1)[0]
        val = round(self._rng.uniform(chosen.min_val, chosen.max_val), 1)
        if chosen.min_val.is_integer() and chosen.max_val.is_integer():
            val = int(val)

        return AffixMod(
            mod_id=f"{chosen.mod_id}_{uuid.uuid4().hex[:4]}",
            mod_name=chosen.mod_name,
            mod_type=affix_type,
            tier=chosen.tier,
            value=val,
            tier_min=chosen.min_val,
            tier_max=chosen.max_val,
            is_downside=chosen.is_downside_affix,
            downside_type=chosen.downside_type,
            downside_val=chosen.downside_val,
            downside_desc=chosen.downside_desc,
        )

    def apply_primal_currency(
        self,
        item: CraftingItem,
        currency: PrimalCurrencyType,
        player_gold: int = 0,
    ) -> CraftingResult:
        """Applies primal currency with exponential gold fee validation and deduction."""
        gold_fee = calculate_crafting_gold_fee(currency, item.item_level)
        if player_gold < gold_fee:
            return CraftingResult(
                success=False,
                status_code="INSUFFICIENT_GOLD_FEE",
                message=f"INSUFFICIENT_GOLD_FEE: Required {gold_fee} gold fee, but player only has {player_gold}.",
                item=item,
                consumed_currency=currency.value,
                gold_fee_consumed=0,
            )
        ok, status, modified_item = self.apply_currency(item, currency)
        return CraftingResult(
            success=ok,
            status_code=status,
            message=status,
            item=modified_item,
            consumed_currency=currency.value,
            gold_fee_consumed=gold_fee if ok else 0,
        )

    def _handle_quality_or_reset(self, item: CraftingItem, currency: PrimalCurrencyType, slot: ItemSlot) -> Tuple[bool, str, CraftingItem]:
        if currency == PrimalCurrencyType.HAC_THACH_MAI_NHAN:
            if slot not in (ItemSlot.WEAPON_1H, ItemSlot.WEAPON_2H):
                return False, "INCOMPATIBLE_SLOT_FOR_WHETSTONE", item
            if item.quality >= 20: return False, "QUALITY_ALREADY_MAX_20", item
            inc = 5 if item.rarity == ItemRarity.NORMAL else (2 if item.rarity == ItemRarity.MAGIC else 1)
            item.quality = min(20, item.quality + inc)
            return True, "QUALITY_INCREASED_SUCCESS", item

        if currency == PrimalCurrencyType.COT_GIAP_THAO_THIET:
            if slot not in (ItemSlot.BODY_ARMOUR, ItemSlot.HELMET, ItemSlot.GLOVES, ItemSlot.BOOTS, ItemSlot.SHIELD):
                return False, "INCOMPATIBLE_SLOT_FOR_ARMOUR_SCRAP", item
            if item.quality >= 20: return False, "QUALITY_ALREADY_MAX_20", item
            inc = 5 if item.rarity == ItemRarity.NORMAL else (2 if item.rarity == ItemRarity.MAGIC else 1)
            item.quality = min(20, item.quality + inc)
            return True, "QUALITY_INCREASED_SUCCESS", item

        if currency == PrimalCurrencyType.TRO_XUONG_TAY_UE:
            if item.rarity == ItemRarity.NORMAL and not (item.prefixes or item.suffixes):
                return False, "CANNOT_SCOUR_NORMAL_ITEM", item
            item.rarity = ItemRarity.NORMAL
            item.prefixes = [m for m in item.prefixes if m.is_fractured]
            item.suffixes = [m for m in item.suffixes if m.is_fractured]
            return True, "SCOUR_SUCCESS", item

        return False, "UNKNOWN_QUALITY_OR_RESET", item

    def _reroll_tier_for_mod(self, slot: ItemSlot, mod: AffixMod, item_lvl: int) -> AffixMod:
        """Rerolls the tier of an existing affix within its canonical family."""
        family_prefix = mod.mod_id.rsplit('_t', 1)[0] if '_t' in mod.mod_id else None
        title = mod.mod_name.split(' (T')[0] if ' (T' in mod.mod_name else mod.mod_name

        match = next(
            (a for a in CANONICAL_AFFIX_DEFINITIONS
             if (family_prefix and a.mod_id.startswith(family_prefix + '_t')) or a.mod_name.startswith(title)),
            None
        )
        if match:
            fam = match.mod_id.rsplit('_t', 1)[0]
            family_defs = [
                a for a in CANONICAL_AFFIX_DEFINITIONS
                if a.mod_id.rsplit('_t', 1)[0] == fam and item_lvl >= a.required_ilvl and slot in a.allowed_slots
            ]
            if family_defs:
                chosen = self._rng.choices(family_defs, weights=[a.weight for a in family_defs], k=1)[0]
                val = round(self._rng.uniform(chosen.min_val, chosen.max_val), 1)
                if chosen.min_val.is_integer() and chosen.max_val.is_integer():
                    val = int(val)
                return AffixMod(
                    mod_id=f"{chosen.mod_id}_{uuid.uuid4().hex[:4]}",
                    mod_name=chosen.mod_name,
                    mod_type=chosen.affix_type,
                    tier=chosen.tier,
                    value=val,
                    tier_min=chosen.min_val,
                    tier_max=chosen.max_val,
                    is_fractured=mod.is_fractured,
                )
        fallback = self._roll_affix(slot, mod.mod_type, item_lvl)
        return fallback if fallback else mod

    def _handle_magic_and_transmute(self, item: CraftingItem, currency: Any, slot: ItemSlot, item_lvl: int) -> Tuple[bool, str, CraftingItem]:
        if currency == PrimalCurrencyType.BAO_MA_THACH:
            if item.rarity != ItemRarity.MAGIC: return False, "REQUIRES_MAGIC_ITEM", item
            item.prefixes = [m for m in item.prefixes if m.is_fractured]
            item.suffixes = [m for m in item.suffixes if m.is_fractured]
            count = self._rng.choice([1, 2])
            for _ in range(count):
                t = AffixType.PREFIX if (len(item.prefixes) == 0 and self._rng.random() < 0.5) else AffixType.SUFFIX
                m = self._roll_affix(slot, t, item_lvl)
                if m: (item.prefixes if t == AffixType.PREFIX else item.suffixes).append(m)
            return True, "ALTERATION_SUCCESS", item

        if currency in (SpiritStoneCurrency.KHAI_LINH_CHAU, PrimalCurrencyType.HAC_SO_THACH):
            if item.rarity == ItemRarity.NORMAL:
                item.rarity = ItemRarity.MAGIC
                item.prefixes = [m for m in item.prefixes if m.is_fractured]
                item.suffixes = [m for m in item.suffixes if m.is_fractured]
                needed = max(1, self._rng.choice([1, 2])) - len(item.prefixes + item.suffixes)
                for _ in range(needed):
                    t = AffixType.PREFIX if len(item.prefixes) < 1 and (len(item.suffixes) >= 1 or self._rng.random() < 0.5) else AffixType.SUFFIX
                    m = self._roll_affix(slot, t, item_lvl)
                    if m: (item.prefixes if t == AffixType.PREFIX else item.suffixes).append(m)
                return True, "TRANSMUTE_SUCCESS", item
            # Reroll Tiers if already Magic/Rare within same canonical families
            for i, mod in enumerate(item.prefixes):
                if not mod.is_fractured:
                    item.prefixes[i] = self._reroll_tier_for_mod(slot, mod, item_lvl)
            for i, mod in enumerate(item.suffixes):
                if not mod.is_fractured:
                    item.suffixes[i] = self._reroll_tier_for_mod(slot, mod, item_lvl)
            return True, "REROLL_TIERS_SUCCESS", item

        if currency == PrimalCurrencyType.CO_COT_AN:
            if item.rarity != ItemRarity.MAGIC: return False, "REQUIRES_MAGIC_ITEM", item
            item.rarity = ItemRarity.RARE
            t = AffixType.PREFIX if len(item.prefixes) < 3 and self._rng.random() < 0.5 else AffixType.SUFFIX
            m = self._roll_affix(slot, t, item_lvl)
            if m: (item.prefixes if t == AffixType.PREFIX else item.suffixes).append(m)
            return True, "REGAL_SUCCESS", item

        return False, "UNKNOWN_MAGIC_CRAFT", item

    def _handle_chaos_reroll(self, item: CraftingItem, slot: ItemSlot, item_lvl: int) -> Tuple[bool, str, CraftingItem]:
        if item.rarity == ItemRarity.NORMAL:
            item.rarity = ItemRarity.MAGIC
            item.prefixes = [m for m in item.prefixes if m.is_fractured]
            item.suffixes = [m for m in item.suffixes if m.is_fractured]
            needed = max(1, self._rng.choice([1, 2])) - len(item.prefixes + item.suffixes)
            for _ in range(needed):
                t = AffixType.PREFIX if len(item.prefixes) < 1 and (len(item.suffixes) >= 1 or self._rng.random() < 0.5) else AffixType.SUFFIX
                m = self._roll_affix(slot, t, item_lvl)
                if m: (item.prefixes if t == AffixType.PREFIX else item.suffixes).append(m)
            return True, "TRANSMUTE_SUCCESS", item

        if item.rarity != ItemRarity.RARE: return False, "REQUIRES_RARE_ITEM", item
        item.prefixes = [m for m in item.prefixes if m.is_fractured]
        item.suffixes = [m for m in item.suffixes if m.is_fractured]
        target = self._rng.randint(3, 6)
        pref_needed = max(0, self._rng.randint(1, min(3, target - 1)) - len(item.prefixes))
        suff_needed = max(0, min(3, target - len(item.prefixes) - pref_needed) - len(item.suffixes))
        for _ in range(pref_needed):
            m = self._roll_affix(slot, AffixType.PREFIX, item_lvl)
            if m and len(item.prefixes) < 3: item.prefixes.append(m)
        for _ in range(suff_needed):
            m = self._roll_affix(slot, AffixType.SUFFIX, item_lvl)
            if m and len(item.suffixes) < 3: item.suffixes.append(m)
        return True, "CHAOS_REROLL_SUCCESS", item

    def _handle_rare_and_chaos(self, item: CraftingItem, currency: Any, slot: ItemSlot, item_lvl: int) -> Tuple[bool, str, CraftingItem]:
        if currency in (SpiritStoneCurrency.HON_NGUYEN_THACH, PrimalCurrencyType.HUYET_HON_THACH):
            return self._handle_chaos_reroll(item, slot, item_lvl)

        if currency in (SpiritStoneCurrency.THIEN_MENH_DAN, PrimalCurrencyType.U_MINH_COT_DINH):
            if item.rarity != ItemRarity.RARE: return False, "REQUIRES_RARE_ITEM", item
            can_p, can_s = len(item.prefixes) < 3, len(item.suffixes) < 3
            if not can_p and not can_s:
                return False, "AFFIXES_FULL_MAX_6", item
            t = AffixType.PREFIX if (can_p and (not can_s or self._rng.random() < 0.5)) else AffixType.SUFFIX
            m = self._roll_affix(slot, t, item_lvl)
            if not m: return False, "NO_VALID_AFFIX_FOR_SLOT", item
            (item.prefixes if t == AffixType.PREFIX else item.suffixes).append(m)
            return True, "EXALT_SUCCESS", item

        if currency in (SpiritStoneCurrency.THAN_TUONG_PHU, PrimalCurrencyType.COT_DAO_TUOC_DOAT):
            unlocked = [(AffixType.PREFIX, i) for i, m in enumerate(item.prefixes) if not m.is_fractured] + \
                       [(AffixType.SUFFIX, i) for i, m in enumerate(item.suffixes) if not m.is_fractured]
            if not unlocked: return False, "ITEM_HAS_NO_AFFIXES", item
            t, idx = self._rng.choice(unlocked)
            (item.prefixes if t == AffixType.PREFIX else item.suffixes).pop(idx)
            return True, "ANNUL_SUCCESS", item

        if currency == PrimalCurrencyType.TINH_HOA_HUYET_THACH:
            if item.rarity not in (ItemRarity.MAGIC, ItemRarity.RARE): return False, "REQUIRES_MAGIC_OR_RARE_ITEM", item
            for mod in item.prefixes + item.suffixes:
                if not mod.is_fractured:
                    min_v, max_v = mod.tier_min, mod.tier_max
                    if min_v == 0.0 and max_v == 0.0:
                        match = next((a for a in CANONICAL_AFFIX_DEFINITIONS if a.mod_name == mod.mod_name or (a.tier == mod.tier and a.affix_type == mod.mod_type)), None)
                        if match: min_v, max_v = match.min_val, match.max_val; mod.tier_min, mod.tier_max = min_v, max_v
                    if max_v > min_v or min_v > 0.0:
                        val = round(self._rng.uniform(min_v, max_v), 1)
                        mod.value = int(val) if float(min_v).is_integer() and float(max_v).is_integer() else val
            return True, "DIVINE_REROLL_SUCCESS", item

        return False, "UNKNOWN_RARE_CRAFT", item

    def _handle_corruption_and_mirror(self, item: CraftingItem, currency: Any, slot: ItemSlot) -> Tuple[bool, str, CraftingItem]:
        if currency == PrimalCurrencyType.TA_HUYET_DI_BIEN_THACH:
            roll = self._rng.random()
            item.is_corrupted = True
            if roll < 0.25:
                item.is_destroyed = True
                item.prefixes.clear()
                item.suffixes.clear()
                return True, "PERMANENT_ANNIHILATION", item
            if roll < 0.50:
                item.implicits.append(AffixMod(f"corrupt_god_{uuid.uuid4().hex[:4]}", "[Tà Huyết Đột Biến] +1 Cấp Toàn Bộ Ma Võ & +4% Trần Kháng", AffixType.CORRUPTED, 0, 1.0))
                return True, "CORRUPTION_GODLY_MUTATION", item
            if roll < 0.75:
                item.rarity = ItemRarity.RARE
                item.prefixes = [m for m in item.prefixes if m.is_fractured]
                item.suffixes = [m for m in item.suffixes if m.is_fractured]
                for _ in range(self._rng.randint(1, 3)):
                    m = self._roll_affix(slot, AffixType.PREFIX, 30)
                    if m: item.prefixes.append(m)
                return True, "CORRUPTION_CHAOS_BRICK", item
            return True, "CORRUPTION_LOCKED_NO_CHANGE", item

        if currency in (SpiritStoneCurrency.THAI_HU_CAN_KHON_KINH, PrimalCurrencyType.HUYET_ANH_CO_KINH):
            if item.rarity not in (ItemRarity.RARE, ItemRarity.MAGIC): return False, "CAN_ONLY_MIRROR_RARE_OR_MAGIC", item
            mirrored = copy.deepcopy(item)
            mirrored.item_uuid = f"mirrored_{uuid.uuid4().hex[:8]}"
            mirrored.is_mirrored = True
            return True, "MIRROR_SUCCESS", mirrored

        return False, "UNKNOWN_SPECIAL_CRAFT", item

    def apply_currency(
        self,
        item: CraftingItem,
        currency: Union[SpiritStoneCurrency, PrimalCurrencyType],
    ) -> Tuple[bool, str, CraftingItem]:
        """Unified entry point for both legacy and primal currencies."""
        if item.is_destroyed: return False, "CANNOT_MODIFY_DESTROYED_ITEM", item
        if item.is_mirrored: return False, "CANNOT_MODIFY_MIRRORED_ITEM", item
        if item.is_corrupted: return False, "CANNOT_MODIFY_CORRUPTED_ITEM", item

        slot = getattr(item, "slot", ItemSlot.WEAPON_1H)
        item_lvl = getattr(item, "item_level", 85)

        if currency == PrimalCurrencyType.UAN_MA_THACH:
            if item.rarity == ItemRarity.MAGIC:
                if len(item.prefixes) + len(item.suffixes) >= 2:
                    return False, "MAGIC_ITEM_AFFIXES_FULL", item
                t = AffixType.PREFIX if len(item.prefixes) == 0 else AffixType.SUFFIX
                m = self._roll_affix(slot, t, item_lvl)
                if m: (item.prefixes if t == AffixType.PREFIX else item.suffixes).append(m)
                return True, "AUGMENT_SUCCESS", item
            elif item.rarity == ItemRarity.RARE:
                item.rarity = ItemRarity.NORMAL
                item.prefixes = [m for m in item.prefixes if m.is_fractured]
                item.suffixes = [m for m in item.suffixes if m.is_fractured]
                return True, "SCOUR_SUCCESS", item
            return False, "CANNOT_SCOUR_NORMAL_ITEM", item

        if currency in (PrimalCurrencyType.HAC_THACH_MAI_NHAN, PrimalCurrencyType.COT_GIAP_THAO_THIET, PrimalCurrencyType.TRO_XUONG_TAY_UE):
            return self._handle_quality_or_reset(item, currency, slot)

        if currency in (SpiritStoneCurrency.KHAI_LINH_CHAU, PrimalCurrencyType.HAC_SO_THACH, PrimalCurrencyType.BAO_MA_THACH, PrimalCurrencyType.CO_COT_AN):
            return self._handle_magic_and_transmute(item, currency, slot, item_lvl)

        if currency in (SpiritStoneCurrency.HON_NGUYEN_THACH, PrimalCurrencyType.HUYET_HON_THACH, SpiritStoneCurrency.THIEN_MENH_DAN,
                        PrimalCurrencyType.U_MINH_COT_DINH, SpiritStoneCurrency.THAN_TUONG_PHU, PrimalCurrencyType.COT_DAO_TUOC_DOAT,
                        PrimalCurrencyType.TINH_HOA_HUYET_THACH):
            return self._handle_rare_and_chaos(item, currency, slot, item_lvl)

        if currency in (PrimalCurrencyType.TA_HUYET_DI_BIEN_THACH, SpiritStoneCurrency.THAI_HU_CAN_KHON_KINH, PrimalCurrencyType.HUYET_ANH_CO_KINH):
            return self._handle_corruption_and_mirror(item, currency, slot)

        return False, "UNKNOWN_CURRENCY", item

    def apply_pinnacle_material(
        self,
        item: CraftingItem,
        material: PrimalCurrencyType,
    ) -> Tuple[bool, str, CraftingItem]:
        """Applies pinnacle materials dropping from Juiced Maps and Endgame Bosses."""
        if item.is_destroyed or item.is_mirrored or item.is_corrupted:
            return False, "CANNOT_MODIFY_SEALED_ITEM", item
        if item.rarity != ItemRarity.RARE:
            return False, "REQUIRES_RARE_ITEM", item

        slot = getattr(item, "slot", ItemSlot.WEAPON_1H)
        if material == PrimalCurrencyType.TINH_HUYET_VIEM_QUY:
            if slot not in (ItemSlot.WEAPON_1H, ItemSlot.WEAPON_2H, ItemSlot.RING, ItemSlot.AMULET):
                return False, "INCOMPATIBLE_SLOT_FOR_FIRE_ESSENCE", item
            item.prefixes = [p for p in item.prefixes if not p.mod_id.startswith("pref_fire_flat")]
            if len(item.prefixes) >= 3:
                item.prefixes.pop()
            fire_def = next((a for a in CANONICAL_AFFIX_DEFINITIONS if a.mod_id == "pref_fire_flat_t1"), None)
            if fire_def:
                val = self._rng.randint(int(fire_def.min_val), int(fire_def.max_val))
                item.prefixes.append(AffixMod(f"pref_fire_flat_t1_{uuid.uuid4().hex[:4]}", fire_def.mod_name, AffixType.PREFIX, 1, val, fire_def.min_val, fire_def.max_val))
                return True, "FLAME_DEMON_ESSENCE_APPLIED_T1", item

        elif material == PrimalCurrencyType.COT_TUY_HAC_LONG:
            unfractured = [m for m in item.prefixes + item.suffixes if not m.is_fractured]
            if not unfractured: return False, "NO_UNFRACTURED_AFFIXES", item
            chosen_mod = self._rng.choice(unfractured)
            chosen_mod.is_fractured = True
            return True, "BLACK_DRAGON_MARROW_FRACTURED_SUCCESS", item

        return False, "UNKNOWN_PINNACLE_MATERIAL", item

    def apply_boneforge_tradeoff_craft(
        self,
        item: CraftingItem,
        mod_id: str,
        unlocked_quest_ids: Set[str],
    ) -> Tuple[bool, str, CraftingItem]:
        """Applies an overpowered cursed trade-off affix at the Primal Boneforge Altar."""
        if item.is_destroyed or item.is_mirrored or item.is_corrupted:
            return False, "CANNOT_MODIFY_SEALED_ITEM", item
        if item.rarity != ItemRarity.RARE:
            return False, "REQUIRES_RARE_ITEM", item

        allowed_quests = {"quest_epic_01_phong_ma_co_tran", "quest_epic_04_van_gioi_than_ma_tranh_ba"}
        if not unlocked_quest_ids.intersection(allowed_quests):
            return False, "PREREQUISITE_QUEST_NOT_COMPLETED", item

        template = get_tradeoff_affix_by_id(mod_id)
        if not template: return False, "INVALID_TRADEOFF_MOD_ID", item
        slot = getattr(item, "slot", ItemSlot.WEAPON_1H)
        if slot not in template.allowed_slots: return False, "INCOMPATIBLE_SLOT_FOR_TRADEOFF", item

        target_list = item.prefixes if template.affix_type == AffixType.PREFIX else item.suffixes
        if len(target_list) >= 3: return False, "AFFIX_SLOT_FULL", item

        val = round(self._rng.uniform(template.min_val, template.max_val), 1)
        if template.min_val.is_integer() and template.max_val.is_integer():
            val = int(val)

        tradeoff_mod = AffixMod(
            mod_id=f"{template.mod_id}_{uuid.uuid4().hex[:4]}",
            mod_name=template.mod_name,
            mod_type=template.affix_type,
            tier=template.tier,
            value=val,
            tier_min=template.min_val,
            tier_max=template.max_val,
            is_downside=True,
            downside_type=template.downside_type,
            downside_val=template.downside_val,
            downside_desc=template.downside_desc,
        )
        target_list.append(tradeoff_mod)
        return True, "BONEFORGE_TRADEOFF_CRAFT_SUCCESS", item
