# app/schemas/syndarix/issue.py
"""
Pydantic schemas for Issue entity.
"""

from datetime import datetime
from typing import Literal
from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator

from .enums import IssuePriority, IssueStatus, SyncStatus


class IssueBase(BaseModel):
    """Base issue schema with common fields."""

    title: str = Field(..., min_length=1, max_length=500)
    body: str = ""
    status: IssueStatus = IssueStatus.OPEN
    priority: IssuePriority = IssuePriority.MEDIUM
    labels: list[str] = Field(default_factory=list)
    story_points: int | None = Field(None, ge=0, le=100)

    @field_validator("title")
    @classmethod
    def validate_title(cls, v: str) -> str:
        """Validate issue title."""
        if not v or v.strip() == "":
            raise ValueError("Issue title cannot be empty")
        return v.strip()

    @field_validator("labels")
    @classmethod
    def validate_labels(cls, v: list[str]) -> list[str]:
        """Validate and normalize labels."""
        return [label.strip().lower() for label in v if label.strip()]


class IssueCreate(IssueBase):
    """Schema for creating a new issue."""

    project_id: UUID
    assigned_agent_id: UUID | None = None
    human_assignee: str | None = Field(None, max_length=255)
    sprint_id: UUID | None = None

    # External tracker fields (optional, for importing from external systems)
    external_tracker_type: Literal["gitea", "github", "gitlab"] | None = None
    external_issue_id: str | None = Field(None, max_length=255)
    remote_url: str | None = Field(None, max_length=1000)
    external_issue_number: int | None = None


class IssueUpdate(BaseModel):
    """Schema for updating an issue."""

    title: str | None = Field(None, min_length=1, max_length=500)
    body: str | None = None
    status: IssueStatus | None = None
    priority: IssuePriority | None = None
    labels: list[str] | None = None
    assigned_agent_id: UUID | None = None
    human_assignee: str | None = Field(None, max_length=255)
    sprint_id: UUID | None = None
    story_points: int | None = Field(None, ge=0, le=100)
    sync_status: SyncStatus | None = None

    @field_validator("title")
    @classmethod
    def validate_title(cls, v: str | None) -> str | None:
        """Validate issue title."""
        if v is not None and (not v or v.strip() == ""):
            raise ValueError("Issue title cannot be empty")
        return v.strip() if v else v

    @field_validator("labels")
    @classmethod
    def validate_labels(cls, v: list[str] | None) -> list[str] | None:
        """Validate and normalize labels."""
        if v is None:
            return v
        return [label.strip().lower() for label in v if label.strip()]


class IssueClose(BaseModel):
    """Schema for closing an issue."""

    resolution: str | None = None  # Optional resolution note


class IssueAssign(BaseModel):
    """Schema for assigning an issue."""

    assigned_agent_id: UUID | None = None
    human_assignee: str | None = Field(None, max_length=255)

    @model_validator(mode="after")
    def validate_assignment(self) -> "IssueAssign":
        """Ensure only one type of assignee is set."""
        if self.assigned_agent_id and self.human_assignee:
            raise ValueError(
                "Cannot assign to both an agent and a human. Choose one."
            )
        return self


class IssueSyncUpdate(BaseModel):
    """Schema for updating sync-related fields."""

    sync_status: SyncStatus
    last_synced_at: datetime | None = None
    external_updated_at: datetime | None = None


class IssueInDB(IssueBase):
    """Schema for issue in database."""

    id: UUID
    project_id: UUID
    assigned_agent_id: UUID | None = None
    human_assignee: str | None = None
    sprint_id: UUID | None = None
    external_tracker_type: str | None = None
    external_issue_id: str | None = None
    remote_url: str | None = None
    external_issue_number: int | None = None
    sync_status: SyncStatus = SyncStatus.SYNCED
    last_synced_at: datetime | None = None
    external_updated_at: datetime | None = None
    closed_at: datetime | None = None
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class IssueResponse(BaseModel):
    """Schema for issue API responses."""

    id: UUID
    project_id: UUID
    title: str
    body: str
    status: IssueStatus
    priority: IssuePriority
    labels: list[str] = Field(default_factory=list)
    assigned_agent_id: UUID | None = None
    human_assignee: str | None = None
    sprint_id: UUID | None = None
    story_points: int | None = None
    external_tracker_type: str | None = None
    external_issue_id: str | None = None
    remote_url: str | None = None
    external_issue_number: int | None = None
    sync_status: SyncStatus = SyncStatus.SYNCED
    last_synced_at: datetime | None = None
    external_updated_at: datetime | None = None
    closed_at: datetime | None = None
    created_at: datetime
    updated_at: datetime

    # Expanded fields from relationships
    project_name: str | None = None
    project_slug: str | None = None
    sprint_name: str | None = None
    assigned_agent_type_name: str | None = None

    model_config = ConfigDict(from_attributes=True)


class IssueListResponse(BaseModel):
    """Schema for paginated issue list responses."""

    issues: list[IssueResponse]
    total: int
    page: int
    page_size: int
    pages: int


class IssueStats(BaseModel):
    """Schema for issue statistics."""

    total: int
    open: int
    in_progress: int
    in_review: int
    blocked: int
    closed: int
    by_priority: dict[str, int]
    total_story_points: int | None = None
    completed_story_points: int | None = None
