"""SDK core types — result containers, plans, and compiled artifacts."""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any, Dict, List, Optional


class Status(str, Enum):
    """Outcome status for a workflow step or overall result."""

    SUCCESS = "success"
    PARTIAL = "partial"
    FAILED = "failed"
    SKIPPED = "skipped"
    NOT_IMPLEMENTED = "not_implemented"


@dataclass
class StepOutcome:
    """Result of a single workflow step.

    Attributes:
        step_name: Identifier matching the ``@workflow_step`` name.
        status: Outcome status.
        data: Arbitrary payload returned by the step.
        started_at: ISO-8601 UTC timestamp when the step began.
        finished_at: ISO-8601 UTC timestamp when the step ended.
        error: Error message if status is FAILED.
        audit_id: Unique ID linking this outcome to the audit trail.
    """

    step_name: str
    status: Status = Status.SUCCESS
    data: Dict[str, Any] = field(default_factory=dict)
    started_at: str = ""
    finished_at: str = ""
    error: Optional[str] = None
    audit_id: str = field(default_factory=lambda: uuid.uuid4().hex[:12])

    def to_dict(self) -> Dict[str, Any]:
        return {
            "step_name": self.step_name,
            "status": self.status.value,
            "data": self.data,
            "started_at": self.started_at,
            "finished_at": self.finished_at,
            "error": self.error,
            "audit_id": self.audit_id,
        }


@dataclass
class Result:
    """Top-level result of a workflow execution.

    Attributes:
        workflow: Dotted workflow name (e.g. ``reconciliation.hash_compare``).
        status: Aggregate status derived from step outcomes.
        steps: Ordered list of step outcomes.
        summary: Human-readable summary of the result.
        metadata: Extra metadata (timing, row counts, etc.).
        result_id: Unique identifier for this result.
        created_at: ISO-8601 UTC timestamp.
    """

    workflow: str
    status: Status = Status.SUCCESS
    steps: List[StepOutcome] = field(default_factory=list)
    summary: str = ""
    metadata: Dict[str, Any] = field(default_factory=dict)
    result_id: str = field(default_factory=lambda: uuid.uuid4().hex[:16])
    created_at: str = field(
        default_factory=lambda: datetime.now(timezone.utc).isoformat()
    )

    def to_dict(self) -> Dict[str, Any]:
        return {
            "workflow": self.workflow,
            "status": self.status.value,
            "steps": [s.to_dict() for s in self.steps],
            "summary": self.summary,
            "metadata": self.metadata,
            "result_id": self.result_id,
            "created_at": self.created_at,
        }


@dataclass
class WorkflowPlan:
    """A planned sequence of workflow steps (used by the agent assistant).

    Attributes:
        workflow: Target workflow name.
        steps: Ordered step names to execute.
        parameters: Resolved parameters for the workflow.
        rationale: LLM-generated explanation for the plan.
        estimated_cost: Optional cost forecast from ``src.agents.cost_forecast``.
    """

    workflow: str
    steps: List[str] = field(default_factory=list)
    parameters: Dict[str, Any] = field(default_factory=dict)
    rationale: str = ""
    estimated_cost: Optional[Dict[str, Any]] = None

    def to_dict(self) -> Dict[str, Any]:
        return {
            "workflow": self.workflow,
            "steps": self.steps,
            "parameters": self.parameters,
            "rationale": self.rationale,
            "estimated_cost": self.estimated_cost,
        }


@dataclass
class CompiledArtifact:
    """Output of the Snowflake compiler.

    Attributes:
        artifact_type: One of ``dynamic_table``, ``task``, ``stored_proc``,
            ``masking_policy``, ``stream``.
        object_name: Fully-qualified Snowflake object name.
        ddl: The generated DDL/SQL statement.
        dependencies: Other object names this artifact depends on.
        source_workflow: Workflow that produced this artifact.
        metadata: Extra compiler metadata.
    """

    artifact_type: str
    object_name: str
    ddl: str
    dependencies: List[str] = field(default_factory=list)
    source_workflow: str = ""
    metadata: Dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "artifact_type": self.artifact_type,
            "object_name": self.object_name,
            "ddl": self.ddl,
            "dependencies": self.dependencies,
            "source_workflow": self.source_workflow,
            "metadata": self.metadata,
        }


@dataclass
class GraphContext:
    """Typed container for graph/IKE enrichment collected during a workflow run.

    Captures everything a workflow learned from graph systems so callers
    can inspect ``result.metadata["graph_context"]`` without digging
    into individual step outcomes.

    Attributes:
        available: Whether any graph system was reachable.
        ike_graph: Raw IKE graph query result (if collected).
        formula_graph: Raw formula dependency graph (if collected).
        lineage_nodes: IDs of lineage nodes recorded during the run.
        evidence_ids: IDs of evidence entries recorded.
        vector_doc_ids: IDs of documents indexed in the vector store.
        kb_edges_ingested: Count of KB graph edges ingested.
        errors: Map of system name → error message for partial failures.
        provenance: Timing and source metadata for auditing.
        trace_id: Correlation ID linking to SDKContext.trace_id.
        collected_at: ISO-8601 UTC timestamp when context was collected.
    """

    available: bool = False
    ike_graph: Optional[Dict[str, Any]] = None
    formula_graph: Optional[Dict[str, Any]] = None
    lineage_nodes: List[str] = field(default_factory=list)
    evidence_ids: List[str] = field(default_factory=list)
    vector_doc_ids: List[str] = field(default_factory=list)
    kb_edges_ingested: int = 0
    errors: Dict[str, str] = field(default_factory=dict)
    provenance: Dict[str, Any] = field(default_factory=dict)
    trace_id: str = ""
    collected_at: str = field(
        default_factory=lambda: datetime.now(timezone.utc).isoformat()
    )

    def to_dict(self) -> Dict[str, Any]:
        return {
            "available": self.available,
            "ike_graph": self.ike_graph,
            "formula_graph": self.formula_graph,
            "lineage_nodes": self.lineage_nodes,
            "evidence_ids": self.evidence_ids,
            "vector_doc_ids": self.vector_doc_ids,
            "kb_edges_ingested": self.kb_edges_ingested,
            "errors": self.errors,
            "provenance": self.provenance,
            "trace_id": self.trace_id,
            "collected_at": self.collected_at,
        }
