import uuid
from datetime import datetime, timezone
from decimal import Decimal
from typing import TYPE_CHECKING, Optional
from sqlalchemy import String, DateTime, Integer, Boolean, Text, Numeric, ForeignKey, CheckConstraint, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.dialects.postgresql import UUID, JSONB, ARRAY
from app.core.database import Base

if TYPE_CHECKING:
    from app.models.user import User
    from app.models.team import Team
    from app.models.account import Account
    from app.models.step_category import StepCategory
    from app.models.session import Session
    from app.models.tree import Tree


class StepLibrary(Base):
    __tablename__ = "step_library"
    __table_args__ = (
        CheckConstraint(
            "step_type IN ('decision', 'action', 'solution')",
            name='ck_step_library_step_type'
        ),
        UniqueConstraint('source_tree_id', 'source_node_id', name='uq_step_library_source_node'),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid.uuid4
    )
    title: Mapped[str] = mapped_column(String(255), nullable=False)
    step_type: Mapped[str] = mapped_column(String(50), nullable=False)
    content: Mapped[dict] = mapped_column(JSONB, nullable=False)

    # Ownership
    created_by: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False
    )
    team_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("teams.id", ondelete="CASCADE"),
        nullable=True
    )
    account_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("accounts.id", ondelete="CASCADE"),
        nullable=True,
        index=True
    )

    # Organization
    category_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("step_categories.id", ondelete="SET NULL"),
        nullable=True
    )
    tags: Mapped[list[str]] = mapped_column(
        ARRAY(String(100)),
        nullable=False,
        default=list
    )

    # Visibility: 'private', 'team', 'public'
    visibility: Mapped[str] = mapped_column(
        String(50),
        nullable=False,
        default="private"
    )

    # Aggregated ratings
    usage_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    rating_average: Mapped[Decimal] = mapped_column(Numeric(3, 2), nullable=False, default=Decimal("0"))
    rating_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    helpful_yes: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    helpful_no: Mapped[int] = mapped_column(Integer, nullable=False, default=0)

    # Flags
    is_featured: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    is_verified: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

    # Timestamps
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc)
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        onupdate=lambda: datetime.now(timezone.utc)
    )

    # Soft delete
    is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)

    # Sync tracking (flow-sourced steps)
    source_tree_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey('trees.id', ondelete='SET NULL'),
        nullable=True,
        index=True
    )
    source_node_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    is_flow_synced: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    last_synced_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)

    # Relationships
    creator: Mapped["User"] = relationship("User", foreign_keys=[created_by])
    team: Mapped[Optional["Team"]] = relationship("Team")
    account: Mapped[Optional["Account"]] = relationship("Account", foreign_keys=[account_id], back_populates="step_library")
    source_tree: Mapped[Optional["Tree"]] = relationship(
        "Tree",
        foreign_keys=[source_tree_id],
        lazy="select"
    )
    category: Mapped[Optional["StepCategory"]] = relationship("StepCategory")
    ratings: Mapped[list["StepRating"]] = relationship("StepRating", back_populates="step", cascade="all, delete-orphan")
    usage_logs: Mapped[list["StepUsageLog"]] = relationship("StepUsageLog", back_populates="step", cascade="all, delete-orphan")


class StepRating(Base):
    __tablename__ = "step_ratings"
    __table_args__ = (
        CheckConstraint('rating >= 1 AND rating <= 5', name='ck_step_ratings_rating_range'),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid.uuid4
    )
    step_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("step_library.id", ondelete="CASCADE"),
        nullable=False
    )
    user_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False
    )
    rating: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    was_helpful: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True)
    review_text: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
    is_verified_use: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    session_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("sessions.id", ondelete="SET NULL"),
        nullable=True
    )
    is_visible: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc)
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        onupdate=lambda: datetime.now(timezone.utc)
    )

    # Relationships
    step: Mapped["StepLibrary"] = relationship("StepLibrary", back_populates="ratings")
    user: Mapped["User"] = relationship("User")
    session: Mapped[Optional["Session"]] = relationship("Session")


class StepUsageLog(Base):
    __tablename__ = "step_usage_log"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid.uuid4
    )
    step_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("step_library.id", ondelete="CASCADE"),
        nullable=False
    )
    user_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False
    )
    session_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("sessions.id", ondelete="CASCADE"),
        nullable=False
    )
    used_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc)
    )

    # Relationships
    step: Mapped["StepLibrary"] = relationship("StepLibrary", back_populates="usage_logs")
    user: Mapped["User"] = relationship("User")
    session: Mapped["Session"] = relationship("Session")
