"""Stage Markers"""
from dataclasses import dataclass
from typing import TYPE_CHECKING, Optional

from structlog import get_logger

from passbook.core.models import User
from passbook.flows.models import Stage
from passbook.policies.engine import PolicyEngine
from passbook.policies.models import PolicyBinding

if TYPE_CHECKING:
    from passbook.flows.planner import FlowPlan

LOGGER = get_logger()


@dataclass
class StageMarker:
    """Base stage marker class, no extra attributes, and has no special handler."""

    # pylint: disable=unused-argument
    def process(self, plan: "FlowPlan", stage: Stage) -> Optional[Stage]:
        """Process callback for this marker. This should be overridden by sub-classes.
        If a stage should be removed, return None."""
        return stage


@dataclass
class ReevaluateMarker(StageMarker):
    """Reevaluate Marker, forces stage's policies to be evaluated again."""

    binding: PolicyBinding
    user: User

    def process(self, plan: "FlowPlan", stage: Stage) -> Optional[Stage]:
        """Re-evaluate policies bound to stage, and if they fail, remove from plan"""
        engine = PolicyEngine(self.binding, self.user)
        engine.use_cache = False
        engine.request.context = plan.context
        engine.build()
        result = engine.result
        if result.passing:
            return stage
        LOGGER.warning(
            "f(plan_inst)[re-eval marker]: stage failed re-evaluation",
            stage=stage,
            messages=result.messages,
        )
        return None