"""Agent planning and execution models for the GuardianHub system.

This module contains Pydantic models for agent planning, mission execution,
and inter-agent communication within the GuardianHub ecosystem.
"""
import time
from typing import List, Dict, Any, Optional, Literal
from uuid import uuid4
from pydantic import BaseModel, Field, ConfigDict,field_validator
from ..registry.registry import register_model
from ...config.settings import settings


# =============================================================================
# Core Planning Models
# =============================================================================

# =============================================================================
# Unified Workflow Spine
# =============================================================================

class PlanStep(BaseModel):
    """The Architect's Intent: Defined by the LLM/Planner."""
    step_id: str = Field(
        default_factory=lambda: f"step_{uuid4().hex[:4]}",
        description="Unique ID for the step."
    )
    step_name: str = Field(..., description="Human-readable name of the step.")
    tool_name: str = Field(..., description="Target tool identifier.")
    tool_args: Dict[str, Any] = Field(default_factory=dict)
    dependencies: List[str] = Field(default_factory=list)
    status: Literal["pending", "running", "complete", "error"] = Field(default="pending")


class ActionStep(PlanStep):
    # 🎯 ALIAS maps the incoming 'tool_name' from PlanStep to 'action_name'
    action_name: str = Field(..., alias="tool_name")

    session_id: str
    trace_id: Optional[str] = None
    agent_name: str = "specialist"
    is_dry_run: bool = False

    model_config = ConfigDict(
        populate_by_name=True,  # 🚀 REQUIRED: Allows mapping during init
        arbitrary_types_allowed=True
    )

# =============================================================================
# Mission Wrappers
# =============================================================================

@register_model
class MacroPlan(BaseModel):
    steps: List[PlanStep] = Field(default_factory=list)
    reflection: Optional[str] = ""
    confidence_score: float = 0.0
    metadata: Dict[str, Any] = Field(default_factory=dict)

    @field_validator('steps')
    @classmethod
    def ensure_step_ids(cls, v: List[PlanStep]) -> List[PlanStep]:
        for i, step in enumerate(v):
            # 🎯 Only generate if it's missing or generic
            if not step.step_id or step.step_id.startswith("step_"):
                # If it's just "step_1", let's make it unique but stable
                if "_" not in step.step_id[5:]:
                    step.step_id = f"step_{i + 1}_{uuid4().hex[:4]}"
        return v


class MacroPlanResponse(BaseModel):
    """Response model for the LLM's planning output."""
    plan: List[PlanStep] = Field(
        default_factory=list,
        description="List of plan steps"
    )
    reflection: Optional[str] = Field(
        default="",
        description="Reasoning behind the plan"
    )


from pydantic import BaseModel, Field, ConfigDict
from typing import List, Dict, Any, Optional
from datetime import datetime





class MissionRequest(BaseModel):
    # 🎯 Data validation logic
    model_config = ConfigDict(populate_by_name=True, arbitrary_types_allowed=True)

    session_id: str
    trace_id: Optional[str] = None
    agent_name: str = "specialist"
    is_dry_run: bool = False
    template_id: str = "NO_TEMPLATE_ID"
    sub_objective: str = "NO_SUB_OBJECTIVE"
    assigned_mission_intent: str= "NO_MISSION_ASSIGNED"
    active_template_id: str = "NO_TEMPLATE_ID"
    mission_dna: str = "Audit Only"
    callback_url: str = settings.endpoints.SUTRAM_CALLBACK_URL
    history_limit: int = 5
    min_success_score: float = 0.7
    risk_threshold: float = 0.7

    # 🚀 The Core Fix: MacroPlan is now a proper model, not just a list
    macro_plan: MacroPlan

    metadata: Dict[str, Any] = Field(default_factory=dict)
    debug_mode: bool = True

    @field_validator('macro_plan')
    @classmethod
    def must_have_steps(cls, v: MacroPlan) -> MacroPlan:
        if not v.steps or len(v.steps) == 0:
            raise ValueError("Mission rejected: Sutram provided an empty MacroPlan.")
        return v

        # 🚀 ADD THIS PROPERTY HERE
    @property
    def technical_context(self) -> Dict[str, Any]:
        """Provides a unified bundle for activity arguments."""
        return {
            "session_id": self.session_id,
            "trace_id": self.trace_id,
            "template_id": self.active_template_id,
            "agent_name": self.agent_name,
            "is_dry_run": self.is_dry_run
        }

