"""
Status Packet and Task Artifacts - Required outputs from every agent run.

Every agent run MUST produce a StatusPacket at the end, containing:
- Progress summary
- Artifacts (diffs, tests, files modified)
- Blockers and next steps
- State changes for project_state.json
"""

from dataclasses import dataclass, field, asdict
from datetime import datetime
from typing import Any
import json


@dataclass
class TaskArtifacts:
    """
    Required outputs from every task.

    These artifacts provide visibility into what the agent accomplished
    and enable the orchestrator to make decisions about next steps.
    """

    # Summary of changes made
    diff_summary: str = ""

    # Tests that were executed
    tests_run: list[str] = field(default_factory=list)

    # Test results breakdown
    test_results: dict[str, int] = field(
        default_factory=lambda: {"passed": 0, "failed": 0, "skipped": 0}
    )

    # Any risky items encountered during execution
    risk_items_encountered: list[str] = field(default_factory=list)

    # Agent's recommendation for next action
    next_action_recommendation: str = ""

    # Files that were modified
    files_modified: list[str] = field(default_factory=list)

    # Git commits created
    commits_created: list[str] = field(default_factory=list)

    # Token usage (if available)
    tokens_input: int = 0
    tokens_output: int = 0

    # Cost (if available)
    cost_usd: float = 0.0

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return asdict(self)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "TaskArtifacts":
        """Create from dictionary."""
        return cls(**{k: v for k, v in data.items() if k in cls.__dataclass_fields__})

    def tests_passed(self) -> bool:
        """Check if all tests passed."""
        return self.test_results.get("failed", 0) == 0

    def has_critical_risks(self) -> bool:
        """Check if any critical risks were encountered."""
        critical_keywords = ["critical", "security", "credential", "secret", "force push"]
        for item in self.risk_items_encountered:
            if any(kw in item.lower() for kw in critical_keywords):
                return True
        return False


@dataclass
class StatusPacket:
    """
    Required output at end of every agent run.

    This is the contract between agents and the orchestrator.
    Every run must produce a StatusPacket to update project state.
    """

    # Identity
    agent_id: str
    task_id: str

    # Timing
    timestamp: datetime = field(default_factory=datetime.now)

    # Status: "completed", "blocked", "failed", "needs_approval"
    status: str = "completed"

    # Human-readable progress summary
    progress_summary: str = ""

    # Detailed artifacts
    artifacts: TaskArtifacts = field(default_factory=TaskArtifacts)

    # Changes to be applied to project_state.json
    state_changes: dict[str, Any] = field(default_factory=dict)

    # Current blockers preventing progress
    blockers: list[str] = field(default_factory=list)

    # Recommended next steps
    next_steps: list[str] = field(default_factory=list)

    # Error message if status is "failed"
    error_message: str = ""

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization."""
        return {
            "agent_id": self.agent_id,
            "task_id": self.task_id,
            "timestamp": self.timestamp.isoformat(),
            "status": self.status,
            "progress_summary": self.progress_summary,
            "artifacts": self.artifacts.to_dict(),
            "state_changes": self.state_changes,
            "blockers": self.blockers,
            "next_steps": self.next_steps,
            "error_message": self.error_message,
        }

    def to_json(self, indent: int = 2) -> str:
        """Convert to JSON string."""
        return json.dumps(self.to_dict(), indent=indent)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "StatusPacket":
        """Create from dictionary."""
        # Handle timestamp
        timestamp = data.get("timestamp")
        if isinstance(timestamp, str):
            timestamp = datetime.fromisoformat(timestamp)
        elif timestamp is None:
            timestamp = datetime.now()

        # Handle artifacts
        artifacts_data = data.get("artifacts", {})
        if isinstance(artifacts_data, dict):
            artifacts = TaskArtifacts.from_dict(artifacts_data)
        else:
            artifacts = TaskArtifacts()

        return cls(
            agent_id=data.get("agent_id", ""),
            task_id=data.get("task_id", ""),
            timestamp=timestamp,
            status=data.get("status", "completed"),
            progress_summary=data.get("progress_summary", ""),
            artifacts=artifacts,
            state_changes=data.get("state_changes", {}),
            blockers=data.get("blockers", []),
            next_steps=data.get("next_steps", []),
            error_message=data.get("error_message", ""),
        )

    @classmethod
    def from_json(cls, json_str: str) -> "StatusPacket":
        """Create from JSON string."""
        return cls.from_dict(json.loads(json_str))

    def is_successful(self) -> bool:
        """Check if the run was successful."""
        return self.status == "completed" and not self.blockers

    def needs_human_intervention(self) -> bool:
        """Check if human intervention is needed."""
        return self.status in ("blocked", "needs_approval") or len(self.blockers) > 0

    def can_continue(self) -> bool:
        """Check if the agent can continue without intervention."""
        return self.status == "completed" and not self.needs_human_intervention()


def create_success_packet(
    agent_id: str,
    task_id: str,
    summary: str,
    files_modified: list[str] = None,
    next_steps: list[str] = None,
) -> StatusPacket:
    """Factory function for creating a successful status packet."""
    return StatusPacket(
        agent_id=agent_id,
        task_id=task_id,
        status="completed",
        progress_summary=summary,
        artifacts=TaskArtifacts(
            files_modified=files_modified or [],
        ),
        next_steps=next_steps or [],
    )


def create_blocked_packet(
    agent_id: str,
    task_id: str,
    summary: str,
    blockers: list[str],
) -> StatusPacket:
    """Factory function for creating a blocked status packet."""
    return StatusPacket(
        agent_id=agent_id,
        task_id=task_id,
        status="blocked",
        progress_summary=summary,
        blockers=blockers,
    )


def create_failed_packet(
    agent_id: str,
    task_id: str,
    error_message: str,
) -> StatusPacket:
    """Factory function for creating a failed status packet."""
    return StatusPacket(
        agent_id=agent_id,
        task_id=task_id,
        status="failed",
        progress_summary=f"Task failed: {error_message}",
        error_message=error_message,
    )


def create_approval_packet(
    agent_id: str,
    task_id: str,
    summary: str,
    action_requiring_approval: str,
) -> StatusPacket:
    """Factory function for creating an approval-needed status packet."""
    return StatusPacket(
        agent_id=agent_id,
        task_id=task_id,
        status="needs_approval",
        progress_summary=summary,
        blockers=[f"Awaiting approval: {action_requiring_approval}"],
    )
