from __future__ import annotations

from sqlalchemy import Column, ForeignKey, Integer, String, Table, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship


class Base(DeclarativeBase):
    pass


class Node(Base):
    """Represents a node in the ToDoWrite system."""

    __tablename__ = "nodes"

    id: Mapped[str] = mapped_column(String, primary_key=True)
    layer: Mapped[str] = mapped_column(String, nullable=False)
    title: Mapped[str] = mapped_column(String, nullable=False)
    description: Mapped[str | None] = mapped_column(Text)
    status: Mapped[str] = mapped_column(String, default="planned")
    progress: Mapped[int | None] = mapped_column(Integer)
    started_date: Mapped[str | None] = mapped_column(String)
    completion_date: Mapped[str | None] = mapped_column(String)
    owner: Mapped[str | None] = mapped_column(String)
    severity: Mapped[str | None] = mapped_column(String)
    work_type: Mapped[str | None] = mapped_column(String)
    assignee: Mapped[str | None] = mapped_column(String)

    labels: Mapped[list[Label]] = relationship(
        secondary="node_labels", back_populates="nodes"
    )
    command: Mapped[Command | None] = relationship(uselist=False, back_populates="node")


class Link(Base):
    """Represents a link between two nodes."""

    __tablename__ = "links"

    parent_id: Mapped[str] = mapped_column(
        String, ForeignKey("nodes.id"), primary_key=True
    )
    child_id: Mapped[str] = mapped_column(
        String, ForeignKey("nodes.id"), primary_key=True
    )


class Label(Base):
    """Represents a label that can be attached to a node."""

    __tablename__ = "labels"

    label: Mapped[str] = mapped_column(String, primary_key=True)

    nodes: Mapped[list[Node]] = relationship(
        secondary="node_labels", back_populates="labels"
    )


node_labels = Table(
    "node_labels",
    Base.metadata,
    Column("node_id", String, ForeignKey("nodes.id"), primary_key=True),
    Column("label", String, ForeignKey("labels.label"), primary_key=True),
)


class Command(Base):
    """Represents a command to be executed."""

    __tablename__ = "commands"

    node_id: Mapped[str] = mapped_column(
        String, ForeignKey("nodes.id"), primary_key=True
    )
    ac_ref: Mapped[str | None] = mapped_column(String)
    run: Mapped[str | None] = mapped_column(Text)

    node: Mapped[Node] = relationship(back_populates="command")
    artifacts: Mapped[list[Artifact]] = relationship(back_populates="command")


class Artifact(Base):
    """Represents an artifact generated by a command."""

    __tablename__ = "artifacts"

    artifact: Mapped[str] = mapped_column(String, primary_key=True)
    command_id: Mapped[str] = mapped_column(
        String, ForeignKey("commands.node_id"), primary_key=True
    )

    command: Mapped[Command] = relationship(back_populates="artifacts")
