import enum
import uuid
from datetime import datetime

from sqlalchemy import DateTime, Enum, Float, ForeignKey, Integer, String, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func

from api.models.base import Base, TimestampMixin, new_uuid


class SuggestionStage(str, enum.Enum):
    suggestion = "suggestion"
    requirement = "requirement"
    promoted = "promoted"
    declined = "declined"


OPEN_SUGGESTION_STAGES = (SuggestionStage.suggestion, SuggestionStage.requirement)


class Suggestion(Base, TimestampMixin):
    __tablename__ = "suggestions"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=new_uuid
    )
    domain_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("domains.id", ondelete="RESTRICT"),
        nullable=False,
        index=True,
    )
    topic_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("topics.id", ondelete="SET NULL"), nullable=True
    )
    workplan_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("workplans.id", ondelete="SET NULL"), nullable=True
    )
    title: Mapped[str] = mapped_column(String(500), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    origin: Mapped[str | None] = mapped_column(String(200), nullable=True)
    origin_ref: Mapped[str | None] = mapped_column(String(200), nullable=True, index=True)
    stage: Mapped[SuggestionStage] = mapped_column(
        Enum(SuggestionStage, name="suggestionstage"),
        nullable=False,
        default=SuggestionStage.suggestion,
        index=True,
    )
    relevance: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
    relevance_events: Mapped[int] = mapped_column(
        Integer, nullable=False, default=0, server_default="0"
    )
    last_requested_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    base_value: Mapped[float] = mapped_column(Float, nullable=False, default=3.0, server_default="3")
    job_size: Mapped[float] = mapped_column(Float, nullable=False, default=3.0, server_default="3")
    relevance_weight: Mapped[float] = mapped_column(
        Float, nullable=False, default=1.0, server_default="1"
    )
    promoted_task_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tasks.id", ondelete="SET NULL"), nullable=True
    )

    domain: Mapped["Domain"] = relationship("Domain", lazy="selectin")  # noqa: F821
    topic: Mapped["Topic | None"] = relationship("Topic", lazy="selectin")  # noqa: F821
    workplan: Mapped["Workplan | None"] = relationship("Workplan", lazy="selectin")  # noqa: F821
    promoted_task: Mapped["Task | None"] = relationship("Task", lazy="selectin")  # noqa: F821
    notes: Mapped[list["SuggestionNote"]] = relationship(
        "SuggestionNote",
        back_populates="suggestion",
        lazy="selectin",
        order_by="SuggestionNote.created_at",
    )

    @property
    def domain_slug(self) -> str:
        return self.domain.slug if self.domain is not None else ""


class SuggestionNote(Base):
    __tablename__ = "suggestion_notes"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=new_uuid)
    suggestion_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("suggestions.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    stage: Mapped[str] = mapped_column(String(30), nullable=False)
    author: Mapped[str | None] = mapped_column(String(100), nullable=True)
    content: Mapped[str] = mapped_column(Text, nullable=False)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )

    suggestion: Mapped["Suggestion"] = relationship("Suggestion", back_populates="notes")


class SuggestionRelevanceBump(Base):
    """Audit trail for relevance bumps; supports debounce lookups."""

    __tablename__ = "suggestion_relevance_bumps"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=new_uuid)
    suggestion_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("suggestions.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    source: Mapped[str] = mapped_column(String(50), nullable=False)
    source_key: Mapped[str] = mapped_column(String(200), nullable=False)
    reason: Mapped[str | None] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )