"""
ncfca/governance/lattice.py

Lattice State Machine for NCFCA components.
Defines the lifecycle states and valid transitions.
"""

from __future__ import annotations
from enum import Enum, auto
from dataclasses import dataclass, field
from typing import List, Dict, Optional


class NodeState(Enum):
    """Possible states in the NCFCA component lifecycle."""
    UNKNOWN = auto()
    OBSERVED = auto()
    VERIFIED = auto()
    OPERATIONAL = auto()
    DEGRADED = auto()
    QUARANTINED = auto()
    REVALIDATING = auto()


@dataclass
class StateTransition:
    """Record of a state change."""
    from_state: NodeState
    to_state: NodeState
    reason: str = ""
    timestamp: float = 0.0


class LatticeStateMachine:
    """
    Manages state transitions for nodes/components according to NCFCA rules.
    Transitions are restricted to valid paths only.
    """

    # Define valid transitions (from_state -> list of allowed to_states)
    VALID_TRANSITIONS: Dict[NodeState, List[NodeState]] = {
        NodeState.UNKNOWN:      [NodeState.OBSERVED, NodeState.VERIFIED],
        NodeState.OBSERVED:     [NodeState.VERIFIED, NodeState.DEGRADED],
        NodeState.VERIFIED:     [NodeState.OPERATIONAL, NodeState.DEGRADED],
        NodeState.OPERATIONAL:  [NodeState.DEGRADED, NodeState.REVALIDATING],
        NodeState.DEGRADED:     [NodeState.OPERATIONAL, NodeState.QUARANTINED, NodeState.REVALIDATING],
        NodeState.QUARANTINED:  [NodeState.REVALIDATING],
        NodeState.REVALIDATING: [NodeState.OPERATIONAL, NodeState.QUARANTINED, NodeState.DEGRADED],
    }

    def __init__(self):
        self.current_state: NodeState = NodeState.UNKNOWN
        self.history: List[StateTransition] = []

    def can_transition(self, to_state: NodeState) -> bool:
        """Check if transition from current state to target state is allowed."""
        allowed = self.VALID_TRANSITIONS.get(self.current_state, [])
        return to_state in allowed

    def transition(self, to_state: NodeState, reason: str = "") -> bool:
        """
        Attempt to move to a new state.
        Returns True if successful, False if transition is invalid.
        """
        if not self.can_transition(to_state):
            return False

        transition = StateTransition(
            from_state=self.current_state,
            to_state=to_state,
            reason=reason,
        )
        self.history.append(transition)
        self.current_state = to_state
        return True

    def force_state(self, new_state: NodeState, reason: str = "Forced by system"):
        """Force a state change (used during Genesis Burn-in or recovery)."""
        transition = StateTransition(
            from_state=self.current_state,
            to_state=new_state,
            reason=reason,
        )
        self.history.append(transition)
        self.current_state = new_state

    def get_history(self) -> List[StateTransition]:
        return self.history.copy()

    def is_healthy(self) -> bool:
        """Returns True if the node is in a healthy operational state."""
        return self.current_state in (NodeState.OPERATIONAL, NodeState.VERIFIED)
