"""
Vạn Giới Kỳ Trân Các (Universal Consignment Vault) Engine for FreeExile.
Provides indexed cross-server search with multi-criteria filtering and executes
atomic Instant Buyout settlements via Distributed Two-Phase Commit (2PC).
"""

import time
import uuid
import threading
from typing import Dict, List, Optional
from dataclasses import dataclass, field
from world.primal_stones_crafting import GearItem, ItemRarity
from trade.two_phase_commit import InstantBuyoutEngine, StashItem


@dataclass
class VaultListing:
    listing_id: str
    seller_id: str
    item: GearItem
    price_currency: str
    price_amount: int
    listed_timestamp: float = field(default_factory=time.time)
    is_sold: bool = False


@dataclass
class VaultItemFilter:
    name_contains: Optional[str] = None
    rarity: Optional[ItemRarity] = None
    min_item_level: Optional[int] = None
    currency: Optional[str] = None
    max_price: Optional[int] = None


class UniversalConsignmentVault:
    def __init__(self, market_tax_rate: float = 0.05, db_path: str = "data/trade_ledger.db"):
        self._lock = threading.RLock()
        self.listings: Dict[str, VaultListing] = {} # listing_id -> VaultListing
        self.item_to_listing: Dict[str, str] = {}   # item_uuid -> listing_id
        self.buyout_engine = InstantBuyoutEngine(market_tax_rate=market_tax_rate, db_path=db_path)

    def list_item_for_sale(
        self,
        seller_id: str,
        item: GearItem,
        price_currency: str,
        price_amount: int
    ) -> str:
        listing_id = f"list_{uuid.uuid4().hex[:12]}"
        listing = VaultListing(
            listing_id=listing_id,
            seller_id=seller_id,
            item=item,
            price_currency=price_currency,
            price_amount=price_amount
        )
        with self._lock:
            self.listings[listing_id] = listing
            self.item_to_listing[item.item_uuid] = listing_id

        # Register in underlying 2PC Buyout Engine
        seller_stash = self.buyout_engine.accounts.get(seller_id)
        if not seller_stash:
            seller_stash = self.buyout_engine.register_account(seller_id)

        stash_item = StashItem(
            item_uuid=item.item_uuid,
            owner_account_id=seller_id,
            item_name=item.item_name,
            asking_price_currency=price_currency,
            asking_price_amount=price_amount
        )
        seller_stash.items[item.item_uuid] = stash_item

        return listing_id

    def search_listings(self, filters: VaultItemFilter) -> List[Dict]:
        with self._lock:
            active_listings = [listg for listg in self.listings.values() if not listg.is_sold]

        results = []
        for listing in active_listings:
            item = listing.item
            if filters.name_contains and filters.name_contains.lower() not in item.item_name.lower():
                continue
            if filters.rarity and item.rarity != filters.rarity:
                continue
            if filters.min_item_level and item.item_level < filters.min_item_level:
                continue
            if filters.currency and listing.price_currency != filters.currency:
                continue
            if filters.max_price and listing.price_amount > filters.max_price:
                continue

            results.append({
                "listing_id": listing.listing_id,
                "item_uuid": item.item_uuid,
                "item_name": item.item_name,
                "item_level": item.item_level,
                "rarity": item.rarity.value,
                "price_currency": listing.price_currency,
                "price_amount": listing.price_amount,
                "seller_id": listing.seller_id,
                "affixes": [a.name for a in item.affixes]
            })

        return results

    def buy_instant(self, buyer_id: str, item_uuid: str) -> tuple:
        """Executes instant buyout via 2PC atomic swap and delists item from vault."""
        with self._lock:
            listing_id = self.item_to_listing.get(item_uuid)
            if not listing_id:
                return False, "Item not listed in vault", None

            listing = self.listings.get(listing_id)
            if not listing or listing.is_sold:
                return False, "Item is already sold or delisted", None
            seller_id = listing.seller_id
            price_currency = listing.price_currency
            price_amount = listing.price_amount

        # Execute 2PC atomic trade
        success, msg, tx_id = self.buyout_engine.execute_instant_buyout(
            buyer_account_id=buyer_id,
            seller_account_id=seller_id,
            item_uuid=item_uuid,
            offered_currency=price_currency,
            offered_amount=price_amount
        )

        if success:
            with self._lock:
                listing.is_sold = True
                self.item_to_listing.pop(item_uuid, None)

        return success, msg, tx_id
