"""Shop service for bargaining, purchases, balance, and personal stats."""
from __future__ import annotations

from typing import Any, Dict, List, Optional

from models.user import User, db
from models.item import Item
from models.inventory_item import InventoryItem


class ShopService:
    """Business logic for item listings and purchases."""

    @classmethod
    def list_available_items(cls, character: Optional[str] = None, query_obj=None) -> List[Dict[str, Any]]:
        # Allow injection of a mock query object for testing
        query = query_obj if query_obj is not None else Item.query.filter(Item.is_sold.is_(False))
        if character:
            query = query.filter(Item.owner_character == character.lower())
        return [item.to_public_dict() for item in query.order_by(Item.id.asc()).all()]

    @classmethod
    def get_item_public(cls, item_id: int) -> Optional[Dict[str, Any]]:
        item = Item.query.get(item_id)
        if not item:
            return None
        return item.to_public_dict()

    @classmethod
    def get_balance(cls, user_id: int) -> Dict[str, Any]:
        user = User.query.get(user_id)
        if not user:
            raise ValueError('User not found')
        return {'gold': user.gold}

    @classmethod
    def purchase_item(cls, user_id: int, item_id: int, paid_price: int) -> Dict[str, Any]:
        user = User.query.get(user_id)
        if not user:
            raise ValueError('User not found')

        item = Item.query.get(item_id)
        if not item:
            raise ValueError('Item not found')

        if item.is_sold:
            raise ValueError('Item is already sold')

        if paid_price <= 0:
            raise ValueError('Paid price must be positive')

        if user.gold < paid_price:
            raise ValueError('Insufficient gold')

        savings_percent = ((item.base_price - paid_price) / item.base_price) * 100 if item.base_price else 0.0

        user.gold -= paid_price
        item.is_sold = True

        entry = InventoryItem(
            user_id=user.id,
            item_id=item.id,
            paid_price=paid_price,
            base_price_revealed=item.base_price,
            savings_percent=round(savings_percent, 2),
            acquired_price=paid_price,  # Set to same as paid_price
        )

        db.session.add(entry)
        db.session.commit()

        return {
            'purchase': entry.to_dict(),
            'balance': {'gold': user.gold},
            'deal_quality': 'good' if savings_percent > 0 else 'bad' if savings_percent < 0 else 'fair',
        }

    @classmethod
    def get_user_inventory(cls, user_id: int) -> List[Dict[str, Any]]:
        entries = (
            InventoryItem.query
            .filter(InventoryItem.user_id == user_id)
            .order_by(InventoryItem.created_at.desc())
            .all()
        )
        return [entry.to_dict() for entry in entries]

    @classmethod
    def get_user_stats(cls, user_id: int) -> Dict[str, Any]:
        entries = cls.get_user_inventory(user_id)
        if not entries:
            return {
                'purchased_count': 0,
                'best_bargain_percent': 0,
                'average_savings_percent': 0,
            }

        savings_values = [float(entry['savings_percent']) for entry in entries]
        average = sum(savings_values) / len(savings_values)

        return {
            'purchased_count': len(entries),
            'best_bargain_percent': round(max(savings_values), 2),
            'average_savings_percent': round(average, 2),
        }

    @classmethod
    def reset_for_tests(cls) -> Dict[str, Any]:
        """Reset shop state for testing: unsell items, reset user gold, clear purchases."""
        # Mark all items as not sold
        Item.query.update({'is_sold': False})

        # Reset all users to 500 gold (initial seed amount per requirements)
        User.query.update({'gold': 500})

        # Clear all inventory items
        InventoryItem.query.delete()

        db.session.commit()

        return {
            'items_reset': Item.query.count(),
            'users_reset': User.query.count(),
            'purchases_cleared': True,
        }
