"""
Checkpoint types for human-in-the-loop interaction.

Provides three checkpoint types for different interaction scenarios:
- HUMAN_VERIFY: Visual/functional verification (90% of checkpoints)
- DECISION: Architectural or implementation choices (9% of checkpoints)
- HUMAN_ACTION: Truly unavoidable manual steps like auth gates (1% of checkpoints)
"""

from dataclasses import dataclass, field
from enum import StrEnum
from typing import Any


class CheckpointType(StrEnum):
    """Types of checkpoints for human-in-the-loop interaction."""

    HUMAN_VERIFY = "human-verify"
    """Visual/functional verification - 90% of checkpoints.
    User reviews what was automated and verifies correctness."""

    DECISION = "decision"
    """Architectural or implementation choice - 9% of checkpoints.
    User selects from available options."""

    HUMAN_ACTION = "human-action"
    """Truly unavoidable manual step - 1% of checkpoints.
    Auth gates, email verification, 2FA codes, etc."""


@dataclass
class Checkpoint:
    """
    Represents a checkpoint in execution requiring human interaction.

    Checkpoints pause execution and wait for user input before continuing.
    They persist across sessions for resumability.

    Attributes:
        type: The checkpoint type (HUMAN_VERIFY, DECISION, HUMAN_ACTION).
        gate: "blocking" or "non-blocking" - whether execution must wait.
        checkpoint_id: Unique identifier for this checkpoint.
        session_id: Session identifier for persistence.

        # HUMAN_VERIFY fields
        what_built: What was automated (for HUMAN_VERIFY).
        how_to_verify: Steps to verify (for HUMAN_VERIFY).

        # DECISION fields
        decision: What's being decided (for DECISION).
        context: Why it matters (for DECISION).
        options: Available options with pros/cons (for DECISION).

        # HUMAN_ACTION fields
        action: Required action (for HUMAN_ACTION).
        instructions: How to perform the action (for HUMAN_ACTION).
        verification: How to verify completion (for HUMAN_ACTION).

        # Common fields
        resume_signal: Prompt for user response.
        timeout_seconds: Optional timeout for the checkpoint.
    """

    type: CheckpointType
    gate: str
    checkpoint_id: str
    session_id: str

    # HUMAN_VERIFY fields
    what_built: str | None = None
    how_to_verify: str | None = None

    # DECISION fields
    decision: str | None = None
    context: str | None = None
    options: list[dict[str, str]] | None = None

    # HUMAN_ACTION fields
    action: str | None = None
    instructions: str | None = None
    verification: str | None = None

    # Common fields
    resume_signal: str = "Type 'approved' or describe issues"
    timeout_seconds: int | None = None

    def __post_init__(self):
        """Validate checkpoint has required fields for its type."""
        if self.gate not in ("blocking", "non-blocking"):
            raise ValueError(
                f"Invalid gate: {self.gate}. Must be 'blocking' or 'non-blocking'"
            )

        if self.type == CheckpointType.HUMAN_VERIFY:
            if not self.what_built:
                raise ValueError("HUMAN_VERIFY checkpoint requires 'what_built'")
            if not self.how_to_verify:
                raise ValueError("HUMAN_VERIFY checkpoint requires 'how_to_verify'")

        elif self.type == CheckpointType.DECISION:
            if not self.decision:
                raise ValueError("DECISION checkpoint requires 'decision'")
            if not self.options:
                raise ValueError("DECISION checkpoint requires 'options'")

        elif self.type == CheckpointType.HUMAN_ACTION:
            if not self.action:
                raise ValueError("HUMAN_ACTION checkpoint requires 'action'")
            if not self.instructions:
                raise ValueError("HUMAN_ACTION checkpoint requires 'instructions'")

    def format_display(self) -> str:
        """
        Format checkpoint for user display.

        Returns:
            Formatted string representation for the user.
        """
        lines = [
            "## CHECKPOINT REACHED",
            "",
            f"**Type:** {self.type.value}",
            f"**Checkpoint ID:** {self.checkpoint_id}",
            f"**Session:** {self.session_id}",
            "",
        ]

        if self.type == CheckpointType.HUMAN_VERIFY:
            lines.extend(
                [
                    "### What Was Built",
                    self.what_built,
                    "",
                    "### How to Verify",
                    self.how_to_verify,
                ]
            )

        elif self.type == CheckpointType.DECISION:
            lines.extend(
                [
                    "### Decision Required",
                    f"**{self.decision}**",
                    "",
                ]
            )
            if self.context:
                lines.extend(
                    [
                        "### Context",
                        self.context,
                        "",
                    ]
                )
            if self.options:
                lines.append("### Options")
                for i, opt in enumerate(self.options, 1):
                    name = opt.get("name", f"Option {i}")
                    pros = opt.get("pros", "")
                    cons = opt.get("cons", "")
                    lines.append(f"{i}. **{name}**")
                    if pros:
                        lines.append(f"   - Pros: {pros}")
                    if cons:
                        lines.append(f"   - Cons: {cons}")

        elif self.type == CheckpointType.HUMAN_ACTION:
            lines.extend(
                [
                    "### Action Required",
                    f"**{self.action}**",
                    "",
                    "### Instructions",
                    self.instructions,
                ]
            )
            if self.verification:
                lines.extend(
                    [
                        "",
                        "### How to Verify Completion",
                        self.verification,
                    ]
                )

        lines.extend(
            [
                "",
                "---",
                f"**Resume Signal:** {self.resume_signal}",
            ]
        )

        if self.timeout_seconds:
            lines.append(f"**Timeout:** {self.timeout_seconds} seconds")

        return "\n".join(lines)

    def to_dict(self) -> dict[str, Any]:
        """
        Serialize checkpoint for persistence.

        Returns:
            Dictionary representation suitable for JSON serialization.
        """
        return {
            "type": self.type.value,
            "gate": self.gate,
            "checkpoint_id": self.checkpoint_id,
            "session_id": self.session_id,
            "what_built": self.what_built,
            "how_to_verify": self.how_to_verify,
            "decision": self.decision,
            "context": self.context,
            "options": self.options,
            "action": self.action,
            "instructions": self.instructions,
            "verification": self.verification,
            "resume_signal": self.resume_signal,
            "timeout_seconds": self.timeout_seconds,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "Checkpoint":
        """
        Deserialize checkpoint from dictionary.

        Args:
            data: Dictionary with checkpoint data.

        Returns:
            Checkpoint instance.
        """
        return cls(
            type=CheckpointType(data["type"]),
            gate=data["gate"],
            checkpoint_id=data["checkpoint_id"],
            session_id=data["session_id"],
            what_built=data.get("what_built"),
            how_to_verify=data.get("how_to_verify"),
            decision=data.get("decision"),
            context=data.get("context"),
            options=data.get("options"),
            action=data.get("action"),
            instructions=data.get("instructions"),
            verification=data.get("verification"),
            resume_signal=data.get(
                "resume_signal", "Type 'approved' or describe issues"
            ),
            timeout_seconds=data.get("timeout_seconds"),
        )
