"""TicketManagerRefactored — Split high-complexity methods for better maintainability."""

from __future__ import annotations

import time
from typing import Any

from proxym.dashboard.tickets._models import (
    JobExecution,
    Milestone,
    MilestoneStatus,
    Sprint,
    SprintStatus,
    Ticket,
    TicketComment,
    TicketPriority,
    TicketStatus,
    TicketType,
    ToolAssignment,
)


class TicketFilter:
    """Extracted filtering logic from TicketManager."""
    
    def __init__(self, manager):
        self.manager = manager
    
    def apply_sprint_filter(self, tickets: list[Ticket], sprint_id: str | None) -> list[Ticket]:
        """Filter tickets by sprint ID."""
        if not sprint_id:
            return tickets
        return [t for t in tickets if t.sprint_id == sprint_id]
    
    def apply_milestone_filter(self, tickets: list[Ticket], milestone_id: str | None) -> list[Ticket]:
        """Filter tickets by milestone ID (via sprint association)."""
        if not milestone_id:
            return tickets
        sprint_ids = {s.id for s in self.manager.sprints.values() if s.milestone_id == milestone_id}
        return [t for t in tickets if t.sprint_id in sprint_ids]
    
    def apply_status_filter(self, tickets: list[Ticket], status: TicketStatus | None) -> list[Ticket]:
        """Filter tickets by status."""
        if not status:
            return tickets
        return [t for t in tickets if t.status == status]
    
    def apply_priority_filter(self, tickets: list[Ticket], priority: TicketPriority | None) -> list[Ticket]:
        """Filter tickets by priority."""
        if not priority:
            return tickets
        return [t for t in tickets if t.priority == priority]
    
    def apply_tool_filter(self, tickets: list[Ticket], tool: str | None) -> list[Ticket]:
        """Filter tickets by assigned tool."""
        if not tool:
            return tickets
        return [t for t in tickets if t.assigned_tool and t.assigned_tool.tool == tool]
    
    def apply_tag_filter(self, tickets: list[Ticket], tag: str | None) -> list[Ticket]:
        """Filter tickets by tag."""
        if not tag:
            return tickets
        return [t for t in tickets if tag in t.tags]
    
    def apply_all_filters(
        self,
        tickets: list[Ticket],
        sprint_id: str | None = None,
        milestone_id: str | None = None,
        status: TicketStatus | None = None,
        priority: TicketPriority | None = None,
        tool: str | None = None,
        tag: str | None = None,
    ) -> list[Ticket]:
        """Apply all filter criteria to ticket list."""
        result = tickets
        
        # Apply filters in sequence - each method has single responsibility
        result = self.apply_sprint_filter(result, sprint_id)
        result = self.apply_milestone_filter(result, milestone_id)
        result = self.apply_status_filter(result, status)
        result = self.apply_priority_filter(result, priority)
        result = self.apply_tool_filter(result, tool)
        result = self.apply_tag_filter(result, tag)
        
        return result


class TicketValidator:
    """Extracted validation logic for ticket operations."""
    
    @staticmethod
    def validate_ticket_data(ticket: Ticket) -> list[str]:
        """Validate ticket data and return list of errors."""
        errors = []
        
        if not ticket.title and not ticket.task:
            errors.append("Ticket must have either title or task")
        
        if ticket.priority not in [p.value for p in TicketPriority]:
            errors.append(f"Invalid priority: {ticket.priority}")
        
        if ticket.status not in [s.value for s in TicketStatus]:
            errors.append(f"Invalid status: {ticket.status}")
        
        if ticket.type and ticket.type not in [t.value for t in TicketType]:
            errors.append(f"Invalid type: {ticket.type}")
        
        return errors
    
    @staticmethod
    def validate_ticket_update(ticket: Ticket, updates: dict[str, Any]) -> list[str]:
        """Validate ticket update data."""
        errors = []
        
        # Check status transitions
        if "status" in updates:
            new_status = updates["status"]
            valid_statuses = [s.value for s in TicketStatus]
            if new_status not in valid_statuses:
                errors.append(f"Invalid status: {new_status}")
        
        # Check priority
        if "priority" in updates:
            new_priority = updates["priority"]
            valid_priorities = [p.value for p in TicketPriority]
            if new_priority not in valid_priorities:
                errors.append(f"Invalid priority: {new_priority}")
        
        return errors


class TicketPersistence:
    """Extracted persistence logic."""
    
    def __init__(self, persist_path=None):
        from pathlib import Path
        self._persist_path: Path | None = persist_path
        self._store = None
        if self._persist_path is not None:
            from proxym.storage import SQLiteNamespaceStore
            self._store = SQLiteNamespaceStore(self._persist_path)
    
    def save(self, data: dict[str, Any]) -> None:
        """Save data to persistence layer."""
        if self._store:
            self._store.save(data)
    
    def load(self) -> dict[str, Any] | None:
        """Load data from persistence layer."""
        if self._store:
            return self._store.load()
        return None


class TicketManagerRefactored:
    """Refactored ticket & sprint store with separated concerns."""

    def __init__(self, persist_path=None):
        self.tickets: dict[str, Ticket] = {}
        self.sprints: dict[str, Sprint] = {}
        self.milestones: dict[str, Milestone] = {}
        
        # Separated concerns
        self.filter = TicketFilter(self)
        self.validator = TicketValidator()
        self.persistence = TicketPersistence(persist_path)
        
        # Load existing data
        if persist_path and persist_path.exists():
            self._load()

    # ── Tickets ───────────────────────────────────────────────

    def create_ticket(self, ticket: Ticket) -> Ticket:
        """Create a new ticket with validation."""
        errors = self.validator.validate_ticket_data(ticket)
        if errors:
            raise ValueError(f"Invalid ticket data: {', '.join(errors)}")
        
        self.tickets[ticket.id] = ticket
        self._save()
        return ticket

    def get_ticket(self, ticket_id: str) -> Ticket | None:
        """Get a single ticket by ID."""
        return self.tickets.get(ticket_id)

    def list_tickets(
        self,
        sprint_id: str | None = None,
        milestone_id: str | None = None,
        status: TicketStatus | None = None,
        priority: TicketPriority | None = None,
        tool: str | None = None,
        tag: str | None = None,
    ) -> list[Ticket]:
        """List tickets with optional filtering."""
        tickets = list(self.tickets.values())
        
        # Use the filter class for clean separation
        filtered = self.filter.apply_all_filters(
            tickets, sprint_id, milestone_id, status, priority, tool, tag
        )
        
        return self._sort_tickets(filtered)

    def update_ticket(self, ticket_id: str, updates: dict[str, Any]) -> Ticket:
        """Update a ticket with validation."""
        if ticket_id not in self.tickets:
            raise ValueError(f"Ticket {ticket_id} not found")
        
        ticket = self.tickets[ticket_id]
        
        # Validate updates
        errors = self.validator.validate_ticket_update(ticket, updates)
        if errors:
            raise ValueError(f"Invalid updates: {', '.join(errors)}")
        
        # Apply updates
        for key, value in updates.items():
            if hasattr(ticket, key):
                setattr(ticket, key, value)
        
        ticket.updated_at = time.time()
        self._save()
        return ticket

    def delete_ticket(self, ticket_id: str) -> bool:
        """Delete a ticket."""
        if ticket_id in self.tickets:
            del self.tickets[ticket_id]
            self._save()
            return True
        return False

    # ── Sprints ───────────────────────────────────────────────

    def create_sprint(self, sprint: Sprint) -> Sprint:
        """Create a new sprint."""
        self.sprints[sprint.id] = sprint
        self._save()
        return sprint

    def list_sprints(self, milestone_id: str | None = None) -> list[Sprint]:
        """List sprints with optional milestone filtering."""
        sprints = list(self.sprints.values())
        if milestone_id:
            sprints = [s for s in sprints if s.milestone_id == milestone_id]
        return sorted(sprints, key=lambda s: s.created_at, reverse=True)

    # ── Milestones ────────────────────────────────────────────

    def create_milestone(self, milestone: Milestone) -> Milestone:
        """Create a new milestone."""
        self.milestones[milestone.id] = milestone
        self._save()
        return milestone

    def list_milestones(self) -> list[Milestone]:
        """List all milestones."""
        return sorted(self.milestones.values(), key=lambda m: m.created_at, reverse=True)

    # ── Private Methods ─────────────────────────────────────────

    def _sort_tickets(self, tickets: list[Ticket]) -> list[Ticket]:
        """Sort tickets by created_at descending."""
        return sorted(tickets, key=lambda t: t.created_at, reverse=True)

    def _save(self) -> None:
        """Save current state to persistence."""
        data = {
            "tickets": {k: v.to_dict() for k, v in self.tickets.items()},
            "sprints": {k: v.to_dict() for k, v in self.sprints.items()},
            "milestones": {k: v.to_dict() for k, v in self.milestones.items()},
        }
        self.persistence.save(data)

    def _load(self) -> None:
        """Load state from persistence."""
        data = self.persistence.load()
        if not data:
            return
        
        # Load tickets
        for ticket_id, ticket_data in data.get("tickets", {}).items():
            self.tickets[ticket_id] = Ticket.from_dict(ticket_data)
        
        # Load sprints
        for sprint_id, sprint_data in data.get("sprints", {}).items():
            self.sprints[sprint_id] = Sprint.from_dict(sprint_data)
        
        # Load milestones
        for milestone_id, milestone_data in data.get("milestones", {}).items():
            self.milestones[milestone_id] = Milestone.from_dict(milestone_data)
