"""
Thread - Single unit of execution on The Grid.

"The smallest unit of computation on The Grid."
"""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, Callable, Any
from enum import Enum
import uuid

from .disc import IdentityDisc


class ThreadStatus(Enum):
    """Status of a Thread."""
    PENDING = "pending"
    RUNNING = "running"
    BLOCKED = "blocked"
    COMPLETED = "completed"
    FAILED = "failed"
    DEREZZED = "derezzed"


@dataclass
class ThreadResult:
    """Result of Thread execution."""
    success: bool
    output: Any = None
    error: Optional[str] = None
    cycles_used: int = 0
    energy_consumed: int = 0


class Thread:
    """
    Thread - Single unit of execution (atomic operation).

    Threads are the smallest executable units on The Grid.
    They perform a single, focused task.
    """

    def __init__(
        self,
        name: str,
        purpose: str,
        block_id: str,
        program_type: str = "program",  # program or recognizer
        blocked_by: list[str] = None,
    ):
        self.id = str(uuid.uuid4())[:8]
        self.name = name
        self.purpose = purpose
        self.block_id = block_id
        self.program_type = program_type
        self.blocked_by = blocked_by or []

        self.status = ThreadStatus.PENDING
        self.created_at = datetime.now()
        self.started_at: Optional[datetime] = None
        self.completed_at: Optional[datetime] = None

        # Progress tracking
        self.progress = 0.0  # 0-100
        self.current_action = "Waiting"
        self.cycles_completed = 0
        self.max_cycles = 10

        # Results
        self.result: Optional[ThreadResult] = None

        # Identity Disc
        self.disc = IdentityDisc(
            program_id=f"thread:{self.id}",
            purpose=purpose,
        )

    def can_start(self, completed_threads: set[str]) -> bool:
        """Check if all blocking threads are completed."""
        if not self.blocked_by:
            return True
        return all(t in completed_threads for t in self.blocked_by)

    def start(self) -> None:
        """Start Thread execution."""
        self.status = ThreadStatus.RUNNING
        self.started_at = datetime.now()
        self.current_action = "Starting..."

    def update_progress(self, progress: float, action: str = None) -> None:
        """Update Thread progress."""
        self.progress = min(100.0, max(0.0, progress))
        if action:
            self.current_action = action
        self.cycles_completed += 1

    def complete(self, result: ThreadResult) -> None:
        """Mark Thread as completed."""
        self.status = ThreadStatus.COMPLETED
        self.completed_at = datetime.now()
        self.result = result
        self.progress = 100.0
        self.current_action = "Completed"

    def fail(self, error: str) -> None:
        """Mark Thread as failed."""
        self.status = ThreadStatus.FAILED
        self.completed_at = datetime.now()
        self.result = ThreadResult(success=False, error=error)
        self.current_action = f"Failed: {error}"

    def derez(self) -> None:
        """Mark Thread as derezzed."""
        self.status = ThreadStatus.DEREZZED
        self.disc.derez()

    def duration(self) -> Optional[float]:
        """Get execution duration in seconds."""
        if not self.started_at:
            return None
        end = self.completed_at or datetime.now()
        return (end - self.started_at).total_seconds()

    def status_icon(self) -> str:
        """Get status icon for display."""
        icons = {
            ThreadStatus.PENDING: "○",
            ThreadStatus.RUNNING: "◐",
            ThreadStatus.BLOCKED: "◌",
            ThreadStatus.COMPLETED: "●",
            ThreadStatus.FAILED: "✗",
            ThreadStatus.DEREZZED: "◯",
        }
        return icons.get(self.status, "?")

    def program_icon(self) -> str:
        """Get program type icon."""
        return "◈" if self.program_type == "recognizer" else "○"

    def progress_bar(self, width: int = 10) -> str:
        """Get visual progress bar."""
        filled = int((self.progress / 100) * width)
        empty = width - filled
        return "█" * filled + "░" * empty

    def display_line(self) -> str:
        """Get single-line display for status views."""
        icon = self.program_icon()
        ptype = "Recognizer" if self.program_type == "recognizer" else "Program"

        if self.status == ThreadStatus.BLOCKED:
            action = f"Blocked by: {', '.join(self.blocked_by)}"
        else:
            action = self.current_action

        progress = f"{self.status_icon()} {self.progress:.0f}%"

        return f"  {icon} {self.name:<16} {ptype:<10} {action:<30} {progress}"

    def to_dict(self) -> dict:
        """Serialize Thread to dictionary."""
        return {
            "id": self.id,
            "name": self.name,
            "purpose": self.purpose,
            "block_id": self.block_id,
            "program_type": self.program_type,
            "status": self.status.value,
            "progress": self.progress,
            "current_action": self.current_action,
            "cycles_completed": self.cycles_completed,
            "blocked_by": self.blocked_by,
            "created_at": self.created_at.isoformat(),
            "started_at": self.started_at.isoformat() if self.started_at else None,
            "completed_at": self.completed_at.isoformat() if self.completed_at else None,
        }

    def __repr__(self) -> str:
        return f"Thread(id={self.id}, name={self.name}, status={self.status.value})"
