"""全部领域枚举。

放在包根、不依赖任何东西 —— models / engine / schemas / api 都从这里取，
保证"状态"这个概念在全仓库只有一份定义。
"""
from __future__ import annotations

from enum import Enum


class StrEnum(str, Enum):
    """Python 3.9 没有 enum.StrEnum，自己来一个。"""

    def __str__(self) -> str:  # pragma: no cover - 只影响日志可读性
        return self.value


# ---------------------------------------------------------------- Run / Step

class RunState(StrEnum):
    QUEUED = "QUEUED"            # 等资源
    PREFLIGHT = "PREFLIGHT"      # 安全门禁 + 环境指纹冻结
    RUNNING = "RUNNING"
    RECOVERING = "RECOVERING"    # 恢复阶梯进行中
    PAUSED = "PAUSED"            # 人工暂停
    FROZEN = "FROZEN"            # 冻结现场，停止一切覆盖性动作（终态）
    COMPLETED = "COMPLETED"      # 终态
    ABORTED = "ABORTED"          # 紧急停止（终态）
    REJECTED = "REJECTED"        # 安全门禁拒绝（终态）


class StepState(StrEnum):
    PENDING = "PENDING"
    DISPATCHED = "DISPATCHED"    # 已租给 Agent，等确认接手
    RUNNING = "RUNNING"
    SUCCEEDED = "SUCCEEDED"
    FAILED = "FAILED"
    TIMED_OUT = "TIMED_OUT"
    SKIPPED = "SKIPPED"
    CANCELLED = "CANCELLED"


class Verdict(StrEnum):
    PASS = "PASS"
    FAIL = "FAIL"
    INCONCLUSIVE = "INCONCLUSIVE"   # 非幂等步骤中断后不自动重跑 → 需人工确认


# ------------------------------------------------------------------ 恢复阶梯

class RecoveryLevel(StrEnum):
    """方案 §7.2 的五级阶梯。顺序即升级顺序。"""

    AGENT_SOFT = "L1_AGENT_SOFT"        # Agent 优雅停止 / 软重启进程
    OS_REBOOT = "L2_OS_REBOOT"          # OS 远程通道重启
    OOB_RESET = "L3_OOB_RESET"          # 带外触发主板 Reset
    OOB_ATX_POWER = "L4_OOB_ATX_POWER"  # 带外模拟 ATX 长按关机再开机
    OOB_AC_CYCLE = "L5_OOB_AC_CYCLE"    # 整机 AC 断电 → 安全间隔 → 上电
    FREEZE = "FREEZE"                   # 冻结现场，不再自动恢复

    @property
    def requires_oob(self) -> bool:
        return self in (
            RecoveryLevel.OOB_RESET,
            RecoveryLevel.OOB_ATX_POWER,
            RecoveryLevel.OOB_AC_CYCLE,
        )


class RecoveryOutcome(StrEnum):
    RECOVERED = "RECOVERED"
    FAILED = "FAILED"
    ESCALATED = "ESCALATED"
    FROZEN = "FROZEN"


class RecoveryTrigger(StrEnum):
    HEARTBEAT_LOST = "HEARTBEAT_LOST"
    STEP_TIMEOUT = "STEP_TIMEOUT"
    HOST_CRASH = "HOST_CRASH"            # 蓝屏 / kernel panic
    DUT_NOT_ENUMERATED = "DUT_NOT_ENUMERATED"
    DATA_INTEGRITY = "DATA_INTEGRITY"    # → 直接 FREEZE，不走阶梯
    MANUAL = "MANUAL"


# -------------------------------------------------------------------- 资产

class HostStatus(StrEnum):
    ONLINE = "ONLINE"
    DEGRADED = "DEGRADED"    # 心跳迟到但未判失联
    OFFLINE = "OFFLINE"
    UNKNOWN = "UNKNOWN"


class DutStatus(StrEnum):
    IDLE = "IDLE"
    IN_USE = "IN_USE"
    QUARANTINED = "QUARANTINED"   # 疑似坏盘，隔离待人工确认
    MISSING = "MISSING"           # 探针找不到


class PowerState(StrEnum):
    ON = "ON"
    OFF = "OFF"
    UNKNOWN = "UNKNOWN"


class DangerLevel(StrEnum):
    NONE = "none"
    LOW = "low"
    HIGH = "high"    # 需要审批记录


# -------------------------------------------------------------------- 失败

class FailureClass(StrEnum):
    """INFRA_FAILURE 必须与 DUT_DEFECT 分开统计 —— 见 domain-model.md。

    把网络断了算成 SSD 缺陷，客户第一周就不信任这套系统。
    """

    DUT_DEFECT = "DUT_DEFECT"
    INFRA_FAILURE = "INFRA_FAILURE"
    SCRIPT_FAILURE = "SCRIPT_FAILURE"
    DATA_INTEGRITY = "DATA_INTEGRITY"
    UNKNOWN = "UNKNOWN"


class IntegrityState(StrEnum):
    OK = "OK"
    MISMATCH = "MISMATCH"
    NOT_CHECKED = "NOT_CHECKED"


# ------------------------------------------------------------- 事件（时间线）

class EventSource(StrEnum):
    CONTROL_PLANE = "control_plane"
    AGENT = "agent"
    OOB = "oob"          # 带外通道 —— 主机死后唯一还在说话的
    HUMAN = "human"


class Severity(StrEnum):
    DEBUG = "DEBUG"
    INFO = "INFO"
    WARNING = "WARNING"
    ERROR = "ERROR"
    CRITICAL = "CRITICAL"


class EventKind(StrEnum):
    """统一时间线的事件种类。

    新增事件种类是常事；删除/改名不是 —— 历史事件已经落库，改名会让旧 Run 的
    时间线读不出来。只增不改。
    """

    # Run 生命周期
    RUN_CREATED = "RUN_CREATED"
    RUN_QUEUED = "RUN_QUEUED"
    RUN_PREFLIGHT_STARTED = "RUN_PREFLIGHT_STARTED"
    RUN_PREFLIGHT_PASSED = "RUN_PREFLIGHT_PASSED"
    RUN_REJECTED = "RUN_REJECTED"
    RUN_STARTED = "RUN_STARTED"
    RUN_PAUSED = "RUN_PAUSED"
    RUN_RESUMED = "RUN_RESUMED"
    RUN_COMPLETED = "RUN_COMPLETED"
    RUN_ABORTED = "RUN_ABORTED"
    RUN_FROZEN = "RUN_FROZEN"

    # 循环与步骤
    LOOP_STARTED = "LOOP_STARTED"
    LOOP_COMPLETED = "LOOP_COMPLETED"
    STEP_DISPATCHED = "STEP_DISPATCHED"
    STEP_LEASE_RENEWED = "STEP_LEASE_RENEWED"
    STEP_LEASE_EXPIRED = "STEP_LEASE_EXPIRED"
    STEP_STARTED = "STEP_STARTED"
    STEP_OUTPUT = "STEP_OUTPUT"
    STEP_SUCCEEDED = "STEP_SUCCEEDED"
    STEP_FAILED = "STEP_FAILED"
    STEP_TIMED_OUT = "STEP_TIMED_OUT"
    STEP_RETRYING = "STEP_RETRYING"
    STEP_CANCELLED = "STEP_CANCELLED"

    # 检查点
    CHECKPOINT_SAVED = "CHECKPOINT_SAVED"
    CHECKPOINT_RESUMED = "CHECKPOINT_RESUMED"

    # 心跳与双通道观测
    HEARTBEAT_DEGRADED = "HEARTBEAT_DEGRADED"
    HEARTBEAT_LOST = "HEARTBEAT_LOST"
    HEARTBEAT_RECOVERED = "HEARTBEAT_RECOVERED"
    OOB_OBSERVATION = "OOB_OBSERVATION"
    OOB_POWER_STATE = "OOB_POWER_STATE"

    # 恢复
    RECOVERY_STARTED = "RECOVERY_STARTED"
    RECOVERY_ESCALATED = "RECOVERY_ESCALATED"
    RECOVERY_SUCCEEDED = "RECOVERY_SUCCEEDED"
    RECOVERY_FAILED = "RECOVERY_FAILED"

    # 设备与数据
    DUT_ENUMERATION_LOST = "DUT_ENUMERATION_LOST"
    DUT_ENUMERATION_RESTORED = "DUT_ENUMERATION_RESTORED"
    INTEGRITY_MISMATCH = "INTEGRITY_MISMATCH"

    # 安全与资源
    SAFETY_APPROVED = "SAFETY_APPROVED"
    SAFETY_REJECTED = "SAFETY_REJECTED"
    LOCK_ACQUIRED = "LOCK_ACQUIRED"
    LOCK_RELEASED = "LOCK_RELEASED"

    # 人与产物
    HUMAN_TOUCH = "HUMAN_TOUCH"     # 每一次人工介入都记 —— UCR 的分母来源
    FAILURE_SIGNED = "FAILURE_SIGNED"
    EVIDENCE_BUNDLED = "EVIDENCE_BUNDLED"


class StepType(StrEnum):
    COMMAND = "command"
    DEVICE_CHECK = "device_check"
    WAIT = "wait"
    LOOP = "loop"
    PRECHECK = "precheck"
    REPORT = "report"


class OnFail(StrEnum):
    RETRY = "retry"
    FAIL_RUN = "fail_run"
    CONTINUE = "continue"
    FREEZE = "freeze"
    RECOVER = "recover"
