"""Pydantic models for beads issue tracker types."""

from datetime import datetime
from typing import Literal, Any

from pydantic import BaseModel, Field, field_validator

# Type aliases for issue statuses, types, and dependencies
#
# IssueStatus and IssueType are strings (not Literals) to support custom
# statuses and types configured via:
#   bd config set status.custom "awaiting_review,awaiting_testing"
#   bd config set types.custom "agent,molecule,event"
#
# The CLI handles validation of these values against the configured options.
# Built-in statuses: open, in_progress, blocked, deferred, closed
# Built-in types: bug, feature, task, epic, chore, decision
IssueStatus = str
IssueType = str
DependencyType = Literal["blocks", "related", "parent-child", "discovered-from"]
OperationAction = Literal["created", "updated", "closed", "reopened"]


# =============================================================================
# CONTEXT ENGINEERING: Minimal Models for List Views
# =============================================================================
# These lightweight models reduce context window usage by ~80% for list operations.
# Use full Issue model only when detailed information is needed (show command).

class IssueMinimal(BaseModel):
    """Minimal issue model for list views (~80% smaller than full Issue).
    
    Use this for ready_work, list_issues, and other bulk operations.
    For full details including dependencies, use Issue model via show().
    """
    id: str
    title: str
    status: IssueStatus
    priority: int = Field(ge=0, le=4)
    issue_type: IssueType
    assignee: str | None = None
    labels: list[str] = Field(default_factory=list)
    dependency_count: int = 0
    dependent_count: int = 0

    @field_validator("priority")
    @classmethod
    def validate_priority(cls, v: int) -> int:
        if not 0 <= v <= 4:
            raise ValueError("Priority must be between 0 and 4")
        return v


class CompactedResult(BaseModel):
    """Result container for compacted list responses.

    When results exceed threshold, returns preview + metadata instead of full data.
    This prevents context window overflow for large issue lists.
    """
    compacted: bool = True
    total_count: int
    preview: list[IssueMinimal]
    preview_count: int
    hint: str = "Use show(issue_id) for full issue details"


class BriefIssue(BaseModel):
    """Ultra-minimal issue for scanning (4 fields).

    Use for quick scans where only identification + priority needed.
    ~95% smaller than full Issue.
    """
    id: str
    title: str
    status: IssueStatus
    priority: int = Field(ge=0, le=4)


class BriefDep(BaseModel):
    """Brief dependency for overview (5 fields).

    Use with brief_deps=True to get full issue but compact dependencies.
    ~90% smaller than full LinkedIssue.
    """
    id: str
    title: str
    status: IssueStatus
    priority: int = Field(ge=0, le=4)
    dependency_type: DependencyType | None = None


class OperationResult(BaseModel):
    """Minimal confirmation for write operations.

    Default response for create/update/close/reopen when verbose=False.
    ~97% smaller than returning full Issue object.
    """
    id: str
    action: OperationAction
    message: str | None = None


# =============================================================================
# ORIGINAL MODELS (unchanged for backward compatibility)
# =============================================================================

class IssueBase(BaseModel):
    """Base issue model with shared fields."""

    id: str
    title: str
    description: str = ""
    design: str | None = None
    acceptance_criteria: str | None = None
    notes: str | None = None
    external_ref: str | None = None
    status: IssueStatus
    priority: int = Field(ge=0, le=4)
    issue_type: IssueType
    created_at: datetime
    updated_at: datetime
    closed_at: datetime | None = None
    assignee: str | None = None
    labels: list[str] = Field(default_factory=list)
    dependency_count: int = 0
    dependent_count: int = 0

    @field_validator("priority")
    @classmethod
    def validate_priority(cls, v: int) -> int:
        """Validate priority is 0-4."""
        if not 0 <= v <= 4:
            raise ValueError("Priority must be between 0 and 4")
        return v


class LinkedIssue(IssueBase):
    """Issue reference in dependencies/dependents (avoids recursion)."""

    dependency_type: DependencyType | None = None


class Issue(IssueBase):
    """Issue model matching bd JSON output."""

    dependencies: list[LinkedIssue] = Field(default_factory=list)
    dependents: list[LinkedIssue] = Field(default_factory=list)


class Dependency(BaseModel):
    """Dependency relationship model."""

    from_id: str
    to_id: str
    dep_type: DependencyType


class CreateIssueParams(BaseModel):
    """Parameters for creating an issue."""

    title: str
    description: str = ""
    design: str | None = None
    acceptance: str | None = None
    external_ref: str | None = None
    priority: int = Field(default=2, ge=0, le=4)
    issue_type: IssueType = "task"
    assignee: str | None = None
    labels: list[str] = Field(default_factory=list)
    id: str | None = None
    deps: list[str] = Field(default_factory=list)


class UpdateIssueParams(BaseModel):
    """Parameters for updating an issue."""

    issue_id: str
    status: IssueStatus | None = None
    priority: int | None = Field(default=None, ge=0, le=4)
    assignee: str | None = None
    title: str | None = None
    description: str | None = None
    design: str | None = None
    acceptance_criteria: str | None = None
    notes: str | None = None
    external_ref: str | None = None


class CloseIssueParams(BaseModel):
    """Parameters for closing an issue."""

    issue_id: str
    reason: str = "Completed"


class ReopenIssueParams(BaseModel):
    """Parameters for reopening issues."""

    issue_ids: list[str]
    reason: str | None = None


class AddDependencyParams(BaseModel):
    """Parameters for adding a dependency."""

    issue_id: str
    depends_on_id: str
    dep_type: DependencyType = "blocks"


class ReadyWorkParams(BaseModel):
    """Parameters for querying ready work."""

    limit: int = Field(default=10, ge=1, le=100)
    priority: int | None = Field(default=None, ge=0, le=4)
    assignee: str | None = None
    labels: list[str] | None = None  # AND: must have ALL labels
    labels_any: list[str] | None = None  # OR: must have at least one
    unassigned: bool = False  # Filter to only unassigned issues
    sort_policy: str | None = None  # hybrid, priority, oldest
    parent_id: str | None = None  # Filter to descendants of this bead/epic


class BlockedParams(BaseModel):
    """Parameters for querying blocked issues."""

    parent_id: str | None = None  # Filter to descendants of this bead/epic


class ListIssuesParams(BaseModel):
    """Parameters for listing issues."""

    status: IssueStatus | None = None
    priority: int | None = Field(default=None, ge=0, le=4)
    issue_type: IssueType | None = None
    assignee: str | None = None
    labels: list[str] | None = None  # AND: must have ALL labels
    labels_any: list[str] | None = None  # OR: must have at least one
    query: str | None = None  # Search in title (case-insensitive)
    unassigned: bool = False  # Filter to only unassigned issues
    limit: int = Field(default=20, ge=1, le=100)  # Reduced to avoid MCP buffer overflow


class ShowIssueParams(BaseModel):
    """Parameters for showing issue details."""

    issue_id: str


class StatsSummary(BaseModel):
    """Summary statistics from bd stats."""

    total_issues: int
    open_issues: int
    in_progress_issues: int
    closed_issues: int
    blocked_issues: int
    deferred_issues: int = 0
    ready_issues: int
    tombstone_issues: int = 0
    pinned_issues: int = 0
    epics_eligible_for_closure: int = 0
    average_lead_time_hours: float


class RecentActivity(BaseModel):
    """Recent activity from bd stats."""

    hours_tracked: int = 24
    commit_count: int = 0
    issues_created: int = 0
    issues_closed: int = 0
    issues_updated: int = 0
    issues_reopened: int = 0
    total_changes: int = 0


class Stats(BaseModel):
    """Beads task statistics matching bd stats --json output."""

    summary: StatsSummary
    recent_activity: RecentActivity | None = None


class BlockedIssue(Issue):
    """Blocked issue with blocking information."""

    blocked_by_count: int
    blocked_by: list[str]


class InitParams(BaseModel):
    """Parameters for initializing bd."""

    prefix: str | None = None


class InitResult(BaseModel):
    """Result from bd init command."""

    database: str
    prefix: str
    message: str
