"""CampaignProgress model for Mantimon TCG.

This module defines the CampaignProgress model for single-player campaign state.
Tracks player progression through clubs, medals, and in-game economy.

Example:
    progress = CampaignProgress(
        user_id=user.id,
        current_club="grass_club",
        medals=["grass_medal"],
        defeated_npcs=["grass_trainer_1", "grass_trainer_2"],
        mantibucks=500
    )
"""

from typing import TYPE_CHECKING
from uuid import UUID

from sqlalchemy import ForeignKey, Integer, String, UniqueConstraint
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.db.base import Base

if TYPE_CHECKING:
    from app.db.models.user import User


class CampaignProgress(Base):
    """Single-player campaign progress.

    Stores all state for a user's campaign playthrough including:
    - Current location in the campaign
    - Medals earned from defeating Club Leaders
    - NPCs defeated (for reward tracking)
    - Win/loss statistics
    - In-game economy (booster packs, Mantibucks)

    Attributes:
        id: Unique identifier (UUID).
        user_id: Foreign key to the user (unique - one campaign per user).
        current_club: ID of the club player is currently at.
        medals: JSONB list of earned medal IDs.
        defeated_npcs: JSONB list of defeated NPC IDs.
        total_wins: Total campaign wins.
        total_losses: Total campaign losses.
        booster_packs: Number of unopened booster packs.
        mantibucks: In-game currency balance.
        created_at: Record creation timestamp.
        updated_at: Record update timestamp.

    Relationships:
        user: The user this progress belongs to.

    Notes:
        - Each user has exactly one CampaignProgress
        - Defeating NPCs grants booster packs (first time only)
        - Mantibucks can be used for card purchases
        - 8 medals required to face Grand Masters
    """

    __tablename__ = "campaign_progress"

    # Ownership (one-to-one with User)
    user_id: Mapped[UUID] = mapped_column(
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        unique=True,
        doc="Foreign key to user (unique - one campaign per user)",
    )

    # Current location
    current_club: Mapped[str] = mapped_column(
        String(50),
        default="grass_club",
        nullable=False,
        doc="ID of current club location",
    )

    # Progress tracking (JSONB for flexible lists)
    medals: Mapped[list] = mapped_column(
        JSONB,
        default=list,
        nullable=False,
        doc="List of earned medal IDs",
    )
    defeated_npcs: Mapped[list] = mapped_column(
        JSONB,
        default=list,
        nullable=False,
        doc="List of defeated NPC IDs (for reward tracking)",
    )

    # Statistics
    total_wins: Mapped[int] = mapped_column(
        Integer,
        default=0,
        nullable=False,
        doc="Total campaign wins",
    )
    total_losses: Mapped[int] = mapped_column(
        Integer,
        default=0,
        nullable=False,
        doc="Total campaign losses",
    )

    # Economy
    booster_packs: Mapped[int] = mapped_column(
        Integer,
        default=0,
        nullable=False,
        doc="Number of unopened booster packs",
    )
    mantibucks: Mapped[int] = mapped_column(
        Integer,
        default=0,
        nullable=False,
        doc="In-game currency balance",
    )

    # Relationship
    user: Mapped["User"] = relationship(
        "User",
        back_populates="campaign_progress",
    )

    # Constraints
    __table_args__ = (UniqueConstraint("user_id", name="uq_campaign_user"),)

    @property
    def medal_count(self) -> int:
        """Get number of medals earned.

        Returns:
            Number of medals in collection.
        """
        return len(self.medals) if self.medals else 0

    @property
    def can_face_grand_masters(self) -> bool:
        """Check if player has enough medals for Grand Masters.

        Returns:
            True if player has 8+ medals.
        """
        return self.medal_count >= 8

    @property
    def win_rate(self) -> float:
        """Calculate win rate percentage.

        Returns:
            Win rate as decimal (0.0 to 1.0), or 0 if no games played.
        """
        total = self.total_wins + self.total_losses
        return self.total_wins / total if total > 0 else 0.0

    def has_defeated(self, npc_id: str) -> bool:
        """Check if an NPC has been defeated.

        Args:
            npc_id: ID of the NPC to check.

        Returns:
            True if NPC is in defeated list.
        """
        return npc_id in (self.defeated_npcs or [])

    def has_medal(self, medal_id: str) -> bool:
        """Check if a medal has been earned.

        Args:
            medal_id: ID of the medal to check.

        Returns:
            True if medal is in collection.
        """
        return medal_id in (self.medals or [])

    def __repr__(self) -> str:
        return (
            f"<CampaignProgress(user_id={self.user_id!r}, "
            f"medals={self.medal_count}, club={self.current_club!r})>"
        )
