import datetime
import uuid
from typing import TYPE_CHECKING

from sqlalchemy import CheckConstraint, ForeignKey, UniqueConstraint
from sqlalchemy import Enum as SAEnum
from sqlalchemy.orm import Mapped, mapped_column, relationship

from idlemaxx.models.activities import Activity
from idlemaxx.models.base import IdlemaxBase
from idlemaxx.models.items import Item

if TYPE_CHECKING:
    from idlemaxx.models.character_combat import CharacterCombatSession, CharacterEquipment
from idlemaxx.models.skills import Skill
from idlemaxx.models.utils import now_utc


class Character(IdlemaxBase):
    __tablename__ = "characters"
    name: Mapped[str] = mapped_column(unique=True)
    discord_user_id: Mapped[str | None] = mapped_column(default=None)

    skills: Mapped[list["CharacterSkill"]] = relationship(default_factory=list, cascade="all, delete-orphan")
    activities: Mapped[list["CharacterActivity"]] = relationship(default_factory=list, cascade="all, delete-orphan")
    items: Mapped[list["CharacterItem"]] = relationship(default_factory=list, cascade="all, delete-orphan")
    activity_queue: Mapped[list["CharacterActivityQueue"]] = relationship(
        default_factory=list, cascade="all, delete-orphan", order_by="CharacterActivityQueue.created_at"
    )
    equipment: Mapped[list["CharacterEquipment"]] = relationship(default_factory=list, cascade="all, delete-orphan")
    combat_sessions: Mapped[list["CharacterCombatSession"]] = relationship(
        default_factory=list, cascade="all, delete-orphan"
    )

    @property
    def current_activity(self) -> "CharacterActivity | None":
        for activity in self.activities:
            if activity.ended_at is None:
                return activity
        return None


class CharacterSkill(IdlemaxBase):
    __tablename__ = "character_skills"
    character_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("characters.id"))
    skill: Mapped[Skill] = mapped_column(SAEnum(Skill))
    experience: Mapped[int] = mapped_column(default=0)

    __table_args__ = (
        UniqueConstraint("character_id", "skill", name="character_id_skill_uc"),
        CheckConstraint("experience >= 0", name="experience_non_negative"),
    )


class CharacterItem(IdlemaxBase):
    __tablename__ = "character_items"
    character_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("characters.id"))
    item: Mapped[Item] = mapped_column(SAEnum(Item))
    quantity: Mapped[int] = mapped_column(default=0)

    __table_args__ = (
        UniqueConstraint("character_id", "item", name="character_id_item_uc"),
        CheckConstraint("quantity >= 0", name="quantity_non_negative"),
    )


class CharacterActivity(IdlemaxBase):
    __tablename__ = "character_activities"
    character_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("characters.id"))
    activity: Mapped[Activity] = mapped_column(SAEnum(Activity))
    action_limit: Mapped[int | None] = mapped_column(default=None)
    started_at: Mapped[datetime.datetime] = mapped_column(default_factory=now_utc, init=False)
    ended_at: Mapped[datetime.datetime | None] = mapped_column(default=None, init=False)

    xp_rewards: Mapped[list["CharacterActivityXpReward"]] = relationship(
        default_factory=list, cascade="all, delete-orphan"
    )
    item_rewards: Mapped[list["CharacterActivityItemReward"]] = relationship(
        default_factory=list, cascade="all, delete-orphan"
    )
    materials_consumed: Mapped[list["CharacterActivityMaterialConsumed"]] = relationship(
        default_factory=list, cascade="all, delete-orphan"
    )

    __table_args__ = (CheckConstraint("ended_at is null or started_at <= ended_at", name="started_before_end"),)


class CharacterActivityXpReward(IdlemaxBase):
    __tablename__ = "character_activity_xp_rewards"
    character_activity_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("character_activities.id"))

    skill: Mapped[Skill] = mapped_column(SAEnum(Skill))
    xp_gained: Mapped[int]


class CharacterActivityItemReward(IdlemaxBase):
    __tablename__ = "character_activity_item_rewards"
    character_activity_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("character_activities.id"))

    item: Mapped[Item] = mapped_column(SAEnum(Item))
    quantity: Mapped[int]


class CharacterActivityMaterialConsumed(IdlemaxBase):
    __tablename__ = "character_activity_materials_consumed"

    character_activity_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("character_activities.id"))
    item: Mapped[Item] = mapped_column(SAEnum(Item))
    quantity: Mapped[int]


class CharacterActivityQueue(IdlemaxBase):
    __tablename__ = "character_activity_queue"
    character_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("characters.id"))
    activity: Mapped[Activity] = mapped_column(SAEnum(Activity))
    action_limit: Mapped[int | None] = mapped_column(default=None)
    started_at: Mapped[datetime.datetime | None] = mapped_column(default=None, init=False)
    # created_at (from IdlemaxBase) = queued_at; ordered by created_at ASC
    # started_at IS NULL  → pending; IS NOT NULL → picked up
