# app/models/syndarix/issue.py
"""
Issue model for Syndarix AI consulting platform.

An Issue represents a unit of work that can be assigned to agents or humans,
with optional synchronization to external issue trackers (Gitea, GitHub, GitLab).
"""

from sqlalchemy import (
    Column,
    Date,
    DateTime,
    Enum,
    ForeignKey,
    Index,
    Integer,
    String,
    Text,
)
from sqlalchemy.dialects.postgresql import (
    JSONB,
    UUID as PGUUID,
)
from sqlalchemy.orm import relationship

from app.models.base import Base, TimestampMixin, UUIDMixin

from .enums import IssuePriority, IssueStatus, IssueType, SyncStatus


class Issue(Base, UUIDMixin, TimestampMixin):
    """
    Issue model representing a unit of work in a project.

    Features:
    - Standard issue fields (title, body, status, priority)
    - Assignment to agent instances or human assignees
    - Sprint association for backlog management
    - External tracker synchronization (Gitea, GitHub, GitLab)
    """

    __tablename__ = "issues"

    # Foreign key to project
    project_id = Column(
        PGUUID(as_uuid=True),
        ForeignKey("projects.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )

    # Parent issue for hierarchy (Epic -> Story -> Task)
    parent_id = Column(
        PGUUID(as_uuid=True),
        ForeignKey("issues.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    # Issue type (Epic, Story, Task, Bug)
    type: Column[IssueType] = Column(
        Enum(IssueType),
        default=IssueType.TASK,
        nullable=False,
        index=True,
    )

    # Reporter (who created this issue - can be user or agent)
    reporter_id = Column(
        PGUUID(as_uuid=True),
        nullable=True,  # System-generated issues may have no reporter
        index=True,
    )

    # Issue content
    title = Column(String(500), nullable=False)
    body = Column(Text, nullable=False, default="")

    # Status and priority
    status: Column[IssueStatus] = Column(
        Enum(IssueStatus),
        default=IssueStatus.OPEN,
        nullable=False,
        index=True,
    )

    priority: Column[IssuePriority] = Column(
        Enum(IssuePriority),
        default=IssuePriority.MEDIUM,
        nullable=False,
        index=True,
    )

    # Labels for categorization (e.g., ["bug", "frontend", "urgent"])
    labels = Column(JSONB, default=list, nullable=False)

    # Assignment - either to an agent or a human (mutually exclusive)
    assigned_agent_id = Column(
        PGUUID(as_uuid=True),
        ForeignKey("agent_instances.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )

    # Human assignee (username or email, not a FK to allow external users)
    human_assignee = Column(String(255), nullable=True, index=True)

    # Sprint association
    sprint_id = Column(
        PGUUID(as_uuid=True),
        ForeignKey("sprints.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )

    # Story points for estimation
    story_points = Column(Integer, nullable=True)

    # Due date for the issue
    due_date = Column(Date, nullable=True, index=True)

    # External tracker integration
    external_tracker_type = Column(
        String(50),
        nullable=True,
        index=True,
    )  # 'gitea', 'github', 'gitlab'

    external_issue_id = Column(String(255), nullable=True)  # External system's ID
    remote_url = Column(String(1000), nullable=True)  # Link to external issue
    external_issue_number = Column(Integer, nullable=True)  # Issue number (e.g., #123)

    # Sync status with external tracker
    sync_status: Column[SyncStatus] = Column(
        Enum(SyncStatus),
        default=SyncStatus.SYNCED,
        nullable=False,
        # Note: Index defined in __table_args__ as ix_issues_sync_status
    )

    last_synced_at = Column(DateTime(timezone=True), nullable=True)
    external_updated_at = Column(DateTime(timezone=True), nullable=True)

    # Lifecycle timestamp
    closed_at = Column(DateTime(timezone=True), nullable=True, index=True)

    # Relationships
    project = relationship("Project", back_populates="issues")
    assigned_agent = relationship(
        "AgentInstance",
        back_populates="assigned_issues",
        foreign_keys=[assigned_agent_id],
    )
    sprint = relationship("Sprint", back_populates="issues")
    parent = relationship("Issue", remote_side="Issue.id", backref="children")

    __table_args__ = (
        Index("ix_issues_project_status", "project_id", "status"),
        Index("ix_issues_project_priority", "project_id", "priority"),
        Index("ix_issues_project_sprint", "project_id", "sprint_id"),
        Index("ix_issues_external_tracker_id", "external_tracker_type", "external_issue_id"),
        Index("ix_issues_sync_status", "sync_status"),
        Index("ix_issues_project_agent", "project_id", "assigned_agent_id"),
        Index("ix_issues_project_type", "project_id", "type"),
        Index("ix_issues_project_status_priority", "project_id", "status", "priority"),
    )

    def __repr__(self) -> str:
        return (
            f"<Issue {self.id} title='{self.title[:30]}...' "
            f"status={self.status.value} priority={self.priority.value}>"
        )
