"""Base context for step-based workflows.

Provides the abstract base class for sharing state between workflow steps.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from synapse_sdk.plugins.context import RuntimeContext
    from synapse_sdk.plugins.steps.base import StepResult


@dataclass
class BaseStepContext:
    """Abstract base context for step-based workflows.

    Provides the common interface for step contexts. Subclass this
    to add action-specific state fields.

    Attributes:
        runtime_ctx: Parent RuntimeContext with logger, env, client.
        step_results: Results from each executed step.
        errors: Accumulated error messages.
        current_step: Name of the currently executing step (set by Orchestrator).

    Example:
        >>> @dataclass
        ... class UploadContext(BaseStepContext):
        ...     params: dict[str, Any] = field(default_factory=dict)
        ...     uploaded_files: list[str] = field(default_factory=list)
        >>>
        >>> ctx = UploadContext(runtime_ctx=runtime_ctx)
        >>> ctx.log('upload_start', {'count': 10})
    """

    runtime_ctx: RuntimeContext
    step_results: list[StepResult] = field(default_factory=list)
    errors: list[str] = field(default_factory=list)
    current_step: str | None = field(default=None, init=False)

    def _set_current_step(self, step_name: str | None) -> None:
        """Set the currently executing step name (internal use by Orchestrator).

        Args:
            step_name: Name of the step being executed, or None to clear.
        """
        self.current_step = step_name

    def log(self, event: str, data: dict[str, Any], file: str | None = None) -> None:
        """Log an event via runtime context.

        Args:
            event: Event name/type.
            data: Dictionary of event data.
            file: Optional file path associated with the event.
        """
        self.runtime_ctx.log(event, data, file)

    def set_progress(self, current: int, total: int, category: str | None = None) -> None:
        """Set progress via runtime context.

        If category is not provided, uses current_step as the category.

        Args:
            current: Current progress value.
            total: Total progress value.
            category: Optional category name. Defaults to current_step if not provided.
        """
        effective_category = category if category is not None else self.current_step
        self.runtime_ctx.set_progress(current, total, effective_category)

    def set_metrics(self, value: dict[str, Any], category: str | None = None) -> None:
        """Set metrics via runtime context.

        If category is not provided, uses current_step as the category.

        Args:
            value: Dictionary of metric values.
            category: Category name. Defaults to current_step if not provided.

        Raises:
            ValueError: If category is not provided and current_step is None.
        """
        effective_category = category if category is not None else self.current_step
        if effective_category is None:
            raise ValueError('category must be provided when not executing within a step (current_step is None)')
        self.runtime_ctx.set_metrics(value, effective_category)
