"""DMS workflow state machine.

Wraps a Document instance and exposes:
  * current_state   — current workflow_status value
  * available_actions(permissions) — list of actions actor can take
  * can_transition(action)         — True if transition is valid from current state
  * transition(action, actor_id, comment) — execute transition (service call)
"""

from __future__ import annotations

from simorgh.apps.dms.workflow.transitions import TRANSITIONS, WorkflowError


class DocumentStateMachine:
    """State machine wrapper around a Document instance.

    Does NOT persist anything — call .transition() which delegates to
    services.trigger_workflow_transition() for persistence.
    """

    def __init__(self, document) -> None:
        self._doc = document

    @property
    def current_state(self) -> str:
        return self._doc.workflow_status or ""

    def can_transition(self, action: str) -> bool:
        """Return True if `action` is valid from the current state."""
        spec = TRANSITIONS.get(action)
        if spec is None:
            return False
        return self.current_state in spec.from_states

    def available_actions(self, permissions: set[str] | None = None) -> list[str]:
        """Return action names available from current state.

        If `permissions` is provided, filter to actions the actor is allowed
        to perform.
        """
        actions = []
        for action, spec in TRANSITIONS.items():
            if self.current_state not in spec.from_states:
                continue
            if permissions is not None and spec.required_permission not in permissions:
                continue
            actions.append(action)
        return actions

    def validate(self, action: str) -> None:
        """Raise WorkflowError if the transition is not valid.

        Does NOT check permissions (caller must do that).
        """
        spec = TRANSITIONS.get(action)
        if spec is None:
            raise WorkflowError(f"Unknown workflow action: {action!r}")
        if self.current_state not in spec.from_states:
            valid_from = ", ".join(sorted(spec.from_states) or ["<initial>"])
            raise WorkflowError(
                f"Cannot perform '{action}' from state '{self.current_state}'. "
                f"Valid from: {valid_from}."
            )
        for validator in spec.validators:
            validator(self._doc)

    def transition(self, action: str, *, actor_id: int, comment: str = "") -> "Document":  # type: ignore[name-defined]
        """Execute transition and return the updated Document.

        Validates the action (raises WorkflowError on failure), then delegates
        to the service layer for persistence and event dispatch.
        """
        from simorgh.apps.dms.workflow.services import trigger_workflow_transition

        self.validate(action)
        return trigger_workflow_transition(
            doc=self._doc,
            action=action,
            actor_id=actor_id,
            comment=comment,
        )
