"""
Issue domain models.

Contains core business entities and value objects for issue management.
"""

from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime, timezone
from enum import Enum

from .exceptions import IssueStateError


class IssueState(Enum):
    """Issue state enumeration."""
    OPEN = "open"
    CLOSED = "closed"
    IN_PROGRESS = "in_progress"


@dataclass(frozen=True)
class Label:
    """Value object representing an issue label."""
    name: str
    color: Optional[str] = None
    description: Optional[str] = None

    def is_state_label(self) -> bool:
        """Check if this is a state-related label."""
        return self.name.startswith('status:')

    def is_priority_label(self) -> bool:
        """Check if this is a priority-related label."""
        return self.name.startswith('priority:')

    def is_type_label(self) -> bool:
        """Check if this is a type-related label."""
        return self.name in ['bug', 'enhancement', 'feature', 'documentation']


@dataclass(frozen=True)
class LabelCategories:
    """Value object for categorized labels."""
    state_labels: List[str]
    priority_labels: List[str]
    type_labels: List[str]
    other_labels: List[str]


@dataclass
class Issue:
    """Issue aggregate root."""
    number: int
    title: str
    state: IssueState
    labels: List[Label]
    created_at: datetime
    updated_at: datetime
    milestone: Optional[str] = None
    assignee: Optional[str] = None
    closed_at: Optional[datetime] = None

    def categorize_labels(self) -> LabelCategories:
        """Categorize labels by type - pure domain logic."""
        state_labels = [label.name for label in self.labels if label.is_state_label()]
        priority_labels = [label.name for label in self.labels if label.is_priority_label()]
        type_labels = [label.name for label in self.labels if label.is_type_label()]
        other_labels = [
            label.name for label in self.labels
            if not (label.is_state_label() or label.is_priority_label() or label.is_type_label())
        ]

        return LabelCategories(
            state_labels=state_labels,
            priority_labels=priority_labels,
            type_labels=type_labels,
            other_labels=other_labels
        )

    def close(self) -> None:
        """Close the issue - domain business rule."""
        if self.state == IssueState.CLOSED:
            raise IssueStateError(
                "Issue is already closed",
                current_state=self.state.value,
                attempted_state=IssueState.CLOSED.value
            )

        self.state = IssueState.CLOSED
        self.closed_at = datetime.now(timezone.utc)

    def reopen(self) -> None:
        """Reopen the issue - domain business rule."""
        if self.state != IssueState.CLOSED:
            raise IssueStateError(
                "Issue is not closed",
                current_state=self.state.value,
                attempted_state=IssueState.OPEN.value
            )

        self.state = IssueState.OPEN
        self.closed_at = None

    def add_label(self, label: Label) -> None:
        """Add a label to the issue."""
        if label not in self.labels:
            self.labels.append(label)

    def remove_label(self, label_name: str) -> None:
        """Remove a label from the issue."""
        self.labels = [label for label in self.labels if label.name != label_name]

    def has_label(self, label_name: str) -> bool:
        """Check if issue has a specific label."""
        return any(label.name == label_name for label in self.labels)