from __future__ import annotations

from enum import Enum
from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field

from app.modules.agent.engine.orchestrator.models.task_spec import Scenario


class ArtifactType(str, Enum):
    TEXT = "text"
    REVIEW_REPORT = "review_report"
    CHANGESET = "changeset"
    DOC_BUNDLE = "doc_bundle"
    GHERKIN_BUNDLE = "gherkin_bundle"
    STRUCTURED_JSON = "structured_json"


class PlanStatus(str, Enum):
    DRAFT = "draft"
    VALIDATED = "validated"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    PARTIAL = "partial"


class InputBinding(BaseModel):
    model_config = ConfigDict(extra="forbid")

    name: str
    from_key: str
    required: bool = True


class ArtifactSpec(BaseModel):
    model_config = ConfigDict(extra="forbid")

    key: str
    type: ArtifactType
    required: bool = True


class RetryPolicy(BaseModel):
    model_config = ConfigDict(extra="forbid")

    max_attempts: int = 1
    backoff_sec: int = 0


class QualityGateRef(BaseModel):
    model_config = ConfigDict(extra="forbid")

    gate_id: str
    blocking: bool = True


class PlanStep(BaseModel):
    model_config = ConfigDict(extra="forbid")

    step_id: str
    title: str
    action_id: str
    executor: Literal["function", "graph"]
    graph_id: str | None = None
    depends_on: list[str] = Field(default_factory=list)
    inputs: list[InputBinding] = Field(default_factory=list)
    outputs: list[ArtifactSpec] = Field(default_factory=list)
    side_effect: Literal["read", "write", "external"] = "read"
    retry: RetryPolicy = Field(default_factory=RetryPolicy)
    timeout_sec: int = 120
    on_failure: Literal["fail", "skip", "replan"] = "fail"
    quality_gates: list[QualityGateRef] = Field(default_factory=list)


class ExecutionPlan(BaseModel):
    model_config = ConfigDict(extra="forbid")

    plan_id: str
    task_id: str
    scenario: Scenario
    template_id: str
    template_version: str
    status: PlanStatus = PlanStatus.DRAFT
    steps: list[PlanStep]
    variables: dict[str, Any] = Field(default_factory=dict)
    global_gates: list[QualityGateRef] = Field(default_factory=list)
