import enum
import uuid
from datetime import datetime

from sqlalchemy import CheckConstraint, DateTime, Enum, ForeignKey, 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_uuid7


class IntakeLane(str, enum.Enum):
    green = "green"
    blue = "blue"
    yellow = "yellow"
    orange = "orange"
    red = "red"


class IntakeStatus(str, enum.Enum):
    open = "open"
    vetted = "vetted"
    routed = "routed"
    closed = "closed"


class IntakeOutcome(str, enum.Enum):
    promoted = "promoted"
    declined = "declined"
    absorbed = "absorbed"


OPEN_INTAKE_STATUSES = (IntakeStatus.open, IntakeStatus.vetted, IntakeStatus.routed)


class Intake(Base, TimestampMixin):
    """A `kind: intake` work record — a spark: idea, finding, directive, or
    request, per canon/standards/work-record-types_v0.1.md. Lifecycle:
    open -> vetted -> routed -> closed(promoted|declined|absorbed).

    Fresh entity per the founder-reviewed architecture draft (2026-07-20,
    WorkOrchestrationArchitectureDraft.md §8 item 6): not a rename/reuse of
    the legacy `suggestions` table.
    """

    __tablename__ = "intakes"
    __table_args__ = (
        CheckConstraint(
            "topic_id IS NOT NULL OR workplan_id IS NOT NULL OR repo_id IS NOT NULL",
            name="ck_intakes_topic_or_workplan_or_repo",
        ),
        CheckConstraint(
            "(status != 'closed') OR (outcome IS NOT NULL)",
            name="ck_intakes_closed_requires_outcome",
        ),
        CheckConstraint(
            "(outcome != 'promoted') OR (promoted_to IS NOT NULL)",
            name="ck_intakes_promoted_requires_promoted_to",
        ),
    )

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=new_uuid7
    )
    topic_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("topics.id", ondelete="SET NULL"), nullable=True, index=True
    )
    workplan_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("workplans.id", ondelete="SET NULL", onupdate="CASCADE"),
        nullable=True,
        index=True,
    )
    repo_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("managed_repos.id", ondelete="SET NULL"), nullable=True, index=True
    )
    title: Mapped[str] = mapped_column(String(500), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    lane: Mapped[IntakeLane] = mapped_column(
        Enum(IntakeLane, name="intakelane"), nullable=False, default=IntakeLane.green
    )
    status: Mapped[IntakeStatus] = mapped_column(
        Enum(IntakeStatus, name="intakestatus"),
        nullable=False,
        default=IntakeStatus.open,
        index=True,
    )
    outcome: Mapped[IntakeOutcome | None] = mapped_column(
        Enum(IntakeOutcome, name="intakeoutcome"), 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)
    promoted_to: Mapped[str | None] = mapped_column(String(200), nullable=True)
    source_repo_path: Mapped[str | None] = mapped_column(
        Text, nullable=True, doc="Repo-relative path of the source file this record was authored in."
    )
    routed_note: Mapped[str | None] = mapped_column(Text, nullable=True)
    closed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)

    topic: Mapped["Topic | None"] = relationship("Topic", lazy="selectin")  # noqa: F821
    workplan: Mapped["Workplan | None"] = relationship("Workplan", lazy="selectin")  # noqa: F821
    repo: Mapped["ManagedRepo | None"] = relationship("ManagedRepo", lazy="selectin")  # noqa: F821
    notes: Mapped[list["IntakeNote"]] = relationship(
        "IntakeNote",
        back_populates="intake",
        lazy="selectin",
        order_by="IntakeNote.created_at",
        cascade="all, delete-orphan",
    )


class IntakeNote(Base):
    __tablename__ = "intake_notes"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=new_uuid7)
    intake_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("intakes.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    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
    )

    intake: Mapped["Intake"] = relationship("Intake", back_populates="notes")
