# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/where-must-an-instance-refuse-to-resume-an-mcp-http-native-streaming-session-after-a-partial-sse-to-websocket-upgrade.md
# Remnant Warrant:    https://corpusfetch.com/c/where-must-an-instance-refuse-to-resume-an-mcp-http-native-streaming-session-after-a-partial-sse-to-websocket-upgrade.warrant.json
# Markdown SHA-256:   0fbb0844ce651ff60be763333af551c9bca36bcd6ba9e4822fa93ebe4182c19e
# Code AST SHA-256:   a56740b81ed2a42317c404f61f5e423e561204387a8cfa9458940341ace70c58
# Verified Classes:   SessionState, NonResumableUpgradeBoundaryError, Session
# Defensive Guards:   3 fail-closed invariants (zero external deps)

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum


class SessionState(Enum):
    SSE_ACTIVE = "sse_active"
    UPGRADE_ACCEPTED_PENDING = "upgrade_accepted_pending"  # event durable, handshake not done
    WEBSOCKET_BOUND = "websocket_bound"
    TERMINATED = "terminated"


class NonResumableUpgradeBoundaryError(RuntimeError):
    """Raised when a resume is requested in the (durable-upgrade-event, handshake-pending) state."""


@dataclass
class Session:
    token: str
    state: SessionState
    upgrade_event_id: int | None = None
    handshake_complete: bool = False


def resume_sse_stream(session: Session, last_event_id: int | None) -> SessionState:
    """Attempt to resume an SSE stream. Refuses at the upgrade boundary."""
    if session.state is SessionState.TERMINATED:
        raise NonResumableUpgradeBoundaryError(
            f"session {session.token} already terminated; open a new session"
        )

    upgrade_pending = (
        session.upgrade_event_id is not None
        and not session.handshake_complete
        and session.state is SessionState.UPGRADE_ACCEPTED_PENDING
    )

    # The three-condition boundary: durable upgrade event, handshake not complete,
    # and a resume request that would treat the upgrade event as a checkpoint.
    if upgrade_pending:
        if last_event_id is None or last_event_id >= session.upgrade_event_id:
            session.state = SessionState.TERMINATED
            raise NonResumableUpgradeBoundaryError(
                f"session {session.token}: cannot resume; upgrade-accepted event "
                f"{session.upgrade_event_id} is durable but WebSocket handshake is pending. "
                f"Session token burned; client must renegotiate with a fresh token."
            )

    if session.state is SessionState.WEBSOCKET_BOUND:
        raise NonResumableUpgradeBoundaryError(
            f"session {session.token} is WebSocket-bound; SSE resume is not applicable"
        )

    return session.state
