///|
pub(all) enum ThreadxEvidenceKind {
  ThreadxEvidenceBspProfile
  ThreadxEvidenceThreadxBuild
  ThreadxEvidenceClockCalibration
  ThreadxEvidenceIrqDispatch
  ThreadxEvidenceDmaRegion
  ThreadxEvidenceMacSmoke
  ThreadxEvidenceCanFdSmoke
  ThreadxEvidenceUartSmoke
  ThreadxEvidenceEmbeddedTrace
  ThreadxEvidenceBoardOracle
} derive(Eq, Debug)

///|
pub fn ThreadxEvidenceKind::label(self : ThreadxEvidenceKind) -> String {
  match self {
    ThreadxEvidenceBspProfile => "bsp-profile"
    ThreadxEvidenceThreadxBuild => "threadx-build"
    ThreadxEvidenceClockCalibration => "clock-calibration"
    ThreadxEvidenceIrqDispatch => "irq-dispatch"
    ThreadxEvidenceDmaRegion => "dma-region"
    ThreadxEvidenceMacSmoke => "mac-smoke"
    ThreadxEvidenceCanFdSmoke => "can-fd-smoke"
    ThreadxEvidenceUartSmoke => "uart-smoke"
    ThreadxEvidenceEmbeddedTrace => "embedded-trace"
    ThreadxEvidenceBoardOracle => "board-oracle"
  }
}

///|
pub(all) struct ThreadxEvidenceRequirement {
  id : String
  kind : ThreadxEvidenceKind
  hook_id : String
  artifact_slot : String
  checker_id : String
  blocked_reason : String
  requires_board : Bool
  requires_threadx_build : Bool
  requires_external_oracle : Bool
  live_evidence_present : Bool
} derive(Eq, Debug)

///|
pub fn ThreadxEvidenceRequirement::is_blocked(
  self : ThreadxEvidenceRequirement,
) -> Bool {
  self.blocked_reason != "" && !self.live_evidence_present
}

///|
pub fn ThreadxEvidenceRequirement::references_hook(
  self : ThreadxEvidenceRequirement,
  hooks : ArrayView[ThreadxHalHookDescriptor],
) -> Bool {
  self.hook_id == "" || hooks.any(fn(hook) { hook.id == self.hook_id })
}

///|
pub(all) struct ThreadxEvidencePlanReport {
  requirement_count : Int
  hook_backed_count : Int
  board_required_count : Int
  threadx_build_required_count : Int
  external_oracle_required_count : Int
  blocked_count : Int
  live_evidence_present_count : Int
  missing_hook_reference_count : Int
  mac_smoke_count : Int
  canfd_smoke_count : Int
  uart_smoke_count : Int
  trace_artifact_count : Int
  board_oracle_count : Int
} derive(Eq, Debug)

///|
pub fn ThreadxEvidencePlanReport::passes_static_plan(
  self : ThreadxEvidencePlanReport,
) -> Bool {
  self.requirement_count == 10 &&
  self.hook_backed_count >= 7 &&
  self.board_required_count == self.requirement_count &&
  self.threadx_build_required_count >= 8 &&
  self.external_oracle_required_count >= 4 &&
  self.blocked_count == self.requirement_count &&
  self.live_evidence_present_count == 0 &&
  self.missing_hook_reference_count == 0 &&
  self.mac_smoke_count == 1 &&
  self.canfd_smoke_count == 1 &&
  self.uart_smoke_count == 1 &&
  self.trace_artifact_count == 1 &&
  self.board_oracle_count == 1
}

///|
pub fn threadx_evidence_requirements() -> Array[ThreadxEvidenceRequirement] {
  [
    evidence_requirement(
      "threadx.evidence.bsp-profile",
      ThreadxEvidenceBspProfile,
      "",
      "board.bsp-profile.json",
      "check-threadx-bsp-profile",
      "缺少选定 STM32 board、toolchain、BSP symbol map 和 memory/DMA placement profile",
      requires_threadx_build=false,
      requires_external_oracle=false,
    ),
    evidence_requirement(
      "threadx.evidence.threadx-build",
      ThreadxEvidenceThreadxBuild,
      "",
      "board.threadx-build-log.txt",
      "check-threadx-build-log",
      "缺少 ThreadX/NetX/EIDE 或等价交叉编译日志与 link map",
      requires_threadx_build=true,
      requires_external_oracle=false,
    ),
    evidence_requirement(
      "threadx.evidence.clock-calibration",
      ThreadxEvidenceClockCalibration,
      "threadx.hook.clock",
      "board.clock-calibration.json",
      "check-threadx-clock-calibration",
      "缺少硬件计数器、比较中断、δ_probe 或 SYNC0/示波器对标证据",
      requires_threadx_build=true,
      requires_external_oracle=true,
    ),
    evidence_requirement(
      "threadx.evidence.irq-dispatch",
      ThreadxEvidenceIrqDispatch,
      "threadx.hook.irq",
      "board.irq-dispatch-log.txt",
      "check-threadx-irq-dispatch",
      "缺少 IRQ bind/dispatch/cleanup 板级日志",
      requires_threadx_build=true,
      requires_external_oracle=false,
    ),
    evidence_requirement(
      "threadx.evidence.dma-region",
      ThreadxEvidenceDmaRegion,
      "threadx.hook.dma",
      "board.dma-region-map.txt",
      "check-threadx-dma-region",
      "缺少 DMA buffer 位于可用 SRAM/非 cache hazard 区域的 link map 或 runtime dump",
      requires_threadx_build=true,
      requires_external_oracle=false,
    ),
    evidence_requirement(
      "threadx.evidence.mac-smoke",
      ThreadxEvidenceMacSmoke,
      "threadx.hook.mac",
      "board.mac-smoke-trace.bin",
      "check-threadx-mac-smoke",
      "缺少 MAC/NetX link up、rx/tx counter、frame echo 或外部抓包证据",
      requires_threadx_build=true,
      requires_external_oracle=true,
    ),
    evidence_requirement(
      "threadx.evidence.canfd-smoke",
      ThreadxEvidenceCanFdSmoke,
      "threadx.hook.canfd",
      "board.canfd-smoke-trace.bin",
      "check-threadx-canfd-smoke",
      "缺少 CAN-FD controller init、tx/rx、error counter 或外部 CAN oracle 证据",
      requires_threadx_build=true,
      requires_external_oracle=true,
    ),
    evidence_requirement(
      "threadx.evidence.uart-rs485-smoke",
      ThreadxEvidenceUartSmoke,
      "threadx.hook.uart",
      "board.uart-rs485-smoke-log.txt",
      "check-threadx-uart-rs485-smoke",
      "缺少 UART/RS-485 idle frame、echo filter、RTU queue 或外部 serial oracle 证据",
      requires_threadx_build=true,
      requires_external_oracle=true,
    ),
    evidence_requirement(
      "threadx.evidence.embedded-trace",
      ThreadxEvidenceEmbeddedTrace,
      "threadx.hook.frame_pool",
      "board.lockwire-embedded-trace.isotrace",
      "check-threadx-embedded-trace",
      "缺少可导入 Lockwire trace/replay 的板级事件 artifact",
      requires_threadx_build=true,
      requires_external_oracle=false,
    ),
    evidence_requirement(
      "threadx.evidence.board-oracle",
      ThreadxEvidenceBoardOracle,
      "threadx.hook.frame_pool",
      "board.evidence-summary.json",
      "check-threadx-board-evidence-summary",
      "缺少汇总 BSP/build/smoke/trace checker 的板级 evidence summary",
      requires_threadx_build=true,
      requires_external_oracle=false,
    ),
  ]
}

///|
pub fn threadx_evidence_plan_report() -> ThreadxEvidencePlanReport {
  let requirements = threadx_evidence_requirements()
  let hooks = threadx_hal_hook_catalog()
  {
    requirement_count: requirements.length(),
    hook_backed_count: count_evidence_where(requirements, fn(item) {
      item.hook_id != ""
    }),
    board_required_count: count_evidence_where(requirements, fn(item) {
      item.requires_board
    }),
    threadx_build_required_count: count_evidence_where(requirements, fn(item) {
      item.requires_threadx_build
    }),
    external_oracle_required_count: count_evidence_where(requirements, fn(
      item,
    ) {
      item.requires_external_oracle
    }),
    blocked_count: count_evidence_where(requirements, fn(item) {
      item.is_blocked()
    }),
    live_evidence_present_count: count_evidence_where(requirements, fn(item) {
      item.live_evidence_present
    }),
    missing_hook_reference_count: count_evidence_where(requirements, fn(item) {
      !item.references_hook(hooks)
    }),
    mac_smoke_count: count_evidence_kind(requirements, ThreadxEvidenceMacSmoke),
    canfd_smoke_count: count_evidence_kind(
      requirements,
      ThreadxEvidenceCanFdSmoke,
    ),
    uart_smoke_count: count_evidence_kind(
      requirements,
      ThreadxEvidenceUartSmoke,
    ),
    trace_artifact_count: count_evidence_kind(
      requirements,
      ThreadxEvidenceEmbeddedTrace,
    ),
    board_oracle_count: count_evidence_kind(
      requirements,
      ThreadxEvidenceBoardOracle,
    ),
  }
}

///|
fn evidence_requirement(
  id : String,
  kind : ThreadxEvidenceKind,
  hook_id : String,
  artifact_slot : String,
  checker_id : String,
  blocked_reason : String,
  requires_threadx_build~ : Bool,
  requires_external_oracle~ : Bool,
) -> ThreadxEvidenceRequirement {
  {
    id,
    kind,
    hook_id,
    artifact_slot,
    checker_id,
    blocked_reason,
    requires_board: true,
    requires_threadx_build,
    requires_external_oracle,
    live_evidence_present: false,
  }
}

///|
fn count_evidence_kind(
  requirements : ArrayView[ThreadxEvidenceRequirement],
  kind : ThreadxEvidenceKind,
) -> Int {
  count_evidence_where(requirements, fn(item) { item.kind == kind })
}

///|
fn count_evidence_where(
  requirements : ArrayView[ThreadxEvidenceRequirement],
  predicate : (ThreadxEvidenceRequirement) -> Bool,
) -> Int {
  let mut count = 0
  for item in requirements {
    if predicate(item) {
      count += 1
    }
  }
  count
}