// Responsibility: bounded, memory-only observation of the existing product hwlab.event.v1 SSE ingress.

import type { WorkbenchSseIngressFrame } from "@/api/workbench-events";
import type { WorkbenchRawHwlabEventWindowCapability } from "@/config/runtime";

export interface RawHwlabIngressRow {
  arrivalSeq: number;
  receivedAt: string;
  eventName: "hwlab.event.v1";
  rawText: string;
  decodeStatus: WorkbenchSseIngressFrame["decodeStatus"];
  byteLength: number;
}

export interface RawHwlabIngressState {
  scopeKey: string;
  receivedCount: number;
  decodedCount: number;
  rejectedCount: number;
  evictedCount: number;
  retainedBytes: number;
  rows: RawHwlabIngressRow[];
}

export function createRawHwlabIngressState(scopeKey = ""): RawHwlabIngressState {
  return {
    scopeKey,
    receivedCount: 0,
    decodedCount: 0,
    rejectedCount: 0,
    evictedCount: 0,
    retainedBytes: 0,
    rows: []
  };
}

export function appendRawHwlabIngressFrame(
  state: RawHwlabIngressState,
  frame: WorkbenchSseIngressFrame,
  capability: WorkbenchRawHwlabEventWindowCapability,
  now: () => number = Date.now
): RawHwlabIngressState {
  if (!capability.enabled || frame.eventName !== "hwlab.event.v1") return state;
  const byteLength = new TextEncoder().encode(frame.rawText).byteLength;
  const row: RawHwlabIngressRow = {
    arrivalSeq: state.receivedCount + 1,
    receivedAt: new Date(now()).toISOString(),
    eventName: "hwlab.event.v1",
    rawText: frame.rawText,
    decodeStatus: frame.decodeStatus,
    byteLength
  };
  const rows = [...state.rows, row];
  let retainedBytes = state.retainedBytes + byteLength;
  let evictedCount = state.evictedCount;
  while (rows.length > capability.maxEntries || retainedBytes > capability.maxRetainedBytes) {
    const evicted = rows.shift();
    if (!evicted) break;
    retainedBytes -= evicted.byteLength;
    evictedCount += 1;
  }
  return {
    ...state,
    receivedCount: state.receivedCount + 1,
    decodedCount: state.decodedCount + (frame.decodeStatus === "accepted" ? 1 : 0),
    rejectedCount: state.rejectedCount + (frame.decodeStatus === "accepted" ? 0 : 1),
    evictedCount,
    retainedBytes,
    rows
  };
}
