"""CheckpointNode — saves progress for interruptible pathways."""

from __future__ import annotations

from datetime import UTC, datetime
from typing import TYPE_CHECKING, Literal
from uuid import uuid4

from core.pathways.models.io import NodeInputs, NodeOutputs
from core.pathways.nodes.base import NodeBase
from core.pathways.nodes.models import CheckpointOutput

if TYPE_CHECKING:
    from core.pathways.context import Context


class CheckpointNode(NodeBase):
    """Checkpoint — saves progress for interruptible pathways.

    Optionally pauses execution for human approval.

    Attributes
    ----------
    checkpoint_id : str | None
        Unique ID for this checkpoint (auto-generated if not set).
    save_keys : list[str] | None
        Which context keys to persist (``None`` = all).
    require_approval : bool
        If true, pauses execution for human approval.
    assignee_role : str | None
        Role required to approve (e.g., ``"manager"``).
    expiry_seconds : int | None
        How long checkpoint is valid (``None`` = forever).
    """

    type: Literal["checkpoint"] = "checkpoint"
    checkpoint_id: str | None = None
    save_keys: list[str] | None = None
    require_approval: bool = False
    assignee_role: str | None = None
    expiry_seconds: int | None = None

    async def compute(self, inputs: NodeInputs, _ctx: Context) -> NodeOutputs:
        """Save checkpoint and optionally pause for approval."""
        # Checkpoint data must be serialisable, so use to_dict() here.
        data = inputs.to_dict()
        cp_id = self.checkpoint_id or f"cp_{uuid4().hex[:8]}"

        if self.save_keys:
            checkpoint_data = {k: data.get(k) for k in self.save_keys if k in data}
        else:
            checkpoint_data = {k: v for k, v in data.items() if not k.startswith("_")}

        checkpoint = {
            "checkpoint_id": cp_id,
            "node_id": self.id,
            "created_at": datetime.now(UTC).isoformat(),
            "data": checkpoint_data,
            "require_approval": self.require_approval,
            "assignee_role": self.assignee_role,
            "expiry_seconds": self.expiry_seconds,
        }

        checkpoint_output = CheckpointOutput(
            checkpoint_id=cp_id,
            saved=True,
            require_approval=self.require_approval,
            assignee_role=self.assignee_role,
            keys_saved=list(checkpoint_data.keys()),
        )
        return NodeOutputs(
            output=checkpoint_output.model_dump(),
            checkpoint=checkpoint,
            pause_execution=self.require_approval,
        )


__all__ = ["CheckpointNode"]
