import type { ForensicsAttribution, ForensicsRun, ForensicsSegment, ForensicsTile } from '@overdeck/deck-ui'

export type Verdict = 'works' | 'broken' | 'missing' | 'unverified'

/** Structural mirror of golive.ts `Criterion`. */
export interface Criterion {
  id: string
  text: string
  verdict: Verdict
  evidence: string | null
  section: string | null
  reachedAt: string | null
}

/** Structural mirror of golive.ts `RepoScore` — the `scoreboard` panel's `data.repos[]`. */
export interface RepoScore {
  repo: string
  works: number
  total: number
  verdicts: { works: number; broken: number; missing: number; unverified: number }
  criteria: Criterion[]
  title: string | null
  summary: string | null
  trend7d: number
  churn: boolean
  commitsSinceLastWorksDelta: number
  sourceUpdatedAt: string | null
}

export interface GolivePanelData {
  repos: RepoScore[]
}

/** Structural mirror of systray.ts `AccountLimitView`/`SystrayPanelData` — the `limits` panel's `data`. */
export interface AccountSpend {
  amount: number | null
  limit: number | null
  currency: string | null
  display: string | null
}

export interface AccountLimitView {
  slug: string
  provider: 'codex' | 'claude'
  label: string
  percent: number | null
  status: string
  spend: AccountSpend | null
  window: { primaryResetAt: number | null; secondaryResetAt: number | null }
  capEtaMinutes: number | null
}

export interface SystrayPanelData {
  stale: boolean
  ageSeconds: number | null
  accounts: AccountLimitView[]
}

/** Structural mirror of ghci.ts's panel-emission shape — the `ci` panel's `data.repos[]`. */
export interface GhciRun {
  id: number
  name: string
  headBranch: string
  status: string
  conclusion: string | null
  htmlUrl: string
  updatedAt: string
}

export interface GhciRunner {
  id: number
  name: string
  status: string
  busy: boolean
  scope?: string
  currentJob: string | null
  currentRepo: string | null
  currentKnown: boolean
}

export interface GhciPr {
  repo: string
  number: number
  title: string
  url: string
  branch: string
  headRefOid: string
  createdAt: string
  ageH: number
  mergeable: 'MERGEABLE' | 'CONFLICTING' | 'UNKNOWN'
  staleVsMain: boolean | null
  checksComplete: boolean
  checks: Array<{
    name: string
    bucket: 'pass' | 'fail' | 'pending' | 'skipping' | 'cancel'
  }>
  trainPr: number | null
}

export interface GhciTrain {
  repo: string
  prNumber: number | null
  prUrl: string | null
  branch: string
  createdAt: string | null
  members: number[]
  state: 'building' | 'gating' | 'failed' | 'rerunning' | 'green' | 'merged' | null
  stateGap: string | null
  gateRun: null | {
    id: number
    attempt: number
    status: string
    conclusion: string | null
    jobsComplete: boolean
    jobs: Array<{
      id: number
      name: string
      status: string
      conclusion: string | null
      runnerId: number | null
      runner: string | null
      startedAt: string | null
      completedAt: string | null
      infraFlag: boolean | null
    }>
  }
  blockedBy: string | null
  infraFlag: boolean | null
}

export interface GhciRepoPanel {
  repo: string
  pollDeferred?: boolean
  degraded: Array<'budget' | 'pagination' | 'jobs'>
  queueComplete: boolean
  historyComplete: boolean
  trainRunsComplete: boolean
  runnersComplete: boolean
  refsComplete: boolean
  prsComplete: boolean
  trainsComplete: boolean
  queueDepth: number | null
  runs: GhciRun[]
  runners: GhciRunner[]
  runnersBusy: number | null
  runnersTotal: number | null
  prQueueDepth: number | null
  oldestQueuedAgeH: number | null
  prs: GhciPr[]
  trains: GhciTrain[]
  lag: {
    landsToday: number | null
    medianOpenToMergeH7d: number | null
    gates: Array<{ runId: number; computeMin: number; wallMin: number }>
    warmedAt: string | null
  }
}

export interface GhciPanelData {
  repos: GhciRepoPanel[]
  runners: GhciRunner[]
  runnersComplete: boolean
  oldestQueuedAgeH: number | null
}

/** Structural mirror of landq-state.ts `LandqTicketState` — one waiting ticket in the local land queue. */
export interface LandqTicketState {
  ticket: string
  branch: string | null
  gateClass: string | null
  ownerPid: number | null
  enqueuedAt: string | null
  waitSeconds: number | null
  queueDepthAtArrival: number | null
  position: number
  ownerLockHeld: boolean | null
  malformed: boolean
}

/** Structural mirror of landq-state.ts `LandqRepoState` — one repo's local land-queue state. */
export interface LandqRepoState {
  repoRoot: string
  project: string
  status: 'ok' | 'absent' | 'error'
  queueDepth: number
  waiting: LandqTicketState[]
  waitingComplete: boolean
  conductorHeld: boolean | null
  conductorHolderPid: number | null
  conductorHolderAgeSeconds: number | null
  conductorComplete: boolean
}

/** Structural mirror of landq-state.ts adapter — the `landq-state` panel's `data`. */
export interface LandqStatePanelData {
  repos: LandqRepoState[]
}

/**
 * Structural mirror of harness.ts `buildPlansPanel` — the `plans` panel's `data.runs[]`.
 * Task fields are forwarded from the harness DAG for per-run observability.
 */
export interface HarnessWaveTask {
  id: string
  status: string
  state?: string
  seat?: string
  deps?: string[]
  attempt?: number
  branch?: string
  model?: string
  binding?: { model?: string }
  durationMs?: number
  gate?: { status?: string; detail?: string }
  review?: { verdict?: string; findings?: Array<{ severity?: string; text?: string }> }
  diff?: { files?: string[]; additions?: number; deletions?: number }
  acceptance?: Array<{ id: string; text: string; result?: 'passed' | 'failed' | 'pending' }>
  alarmed?: boolean
}

export interface HarnessWave {
  wave: number
  tasks: HarnessWaveTask[]
}

export interface HarnessPlanRun {
  runId: string
  seq: number
  title: string
  status: string
  state: string
  owner: string
  currentTask: string | null
  tasksTotal: number
  tasksCompleted: number
  pendingDecisions: number
  degradedReason: string
  updatedAt: string | null
  startedAt?: string | null
  currentActivityStartedAt?: string | null
  repoRoot: string
  /** Attempts of the same plan the engine folded into this row; 1 when it ran once. */
  attempts?: number
  attemptRunIds?: string[]
  registry?: {
    slug?: string
    created?: string
    projectName?: string
    topic?: string
  }
  failClass?: string
  abandoned: boolean
  abandonedAt: string | null
  alarmed?: boolean
  waves: HarnessWave[]
}

/** Structural mirror of harness.ts `HarnessQueueEntry` — the `plans` panel's `data.queue[]`. */
export interface HarnessQueueEntry {
  id: string
  repo: string
  slug: string
  preset: string | null
  account: string | null
  addedAt: string
  status: string
  attempt: number
  runId: string | null
  window: unknown | null
  nextEligibleAt: string | null
  bypassRequestedAt: string | null
  terminalAt: string | null
  failure: unknown | null
}

export interface HarnessPlansPanelData {
  runs: HarnessPlanRun[]
  queue?: HarnessQueueEntry[]
}

/** `forensics:<runId>` panel's `data` — same shape KpiTile/PhaseBars/RunLanes already consume. */
export interface ForensicsPanelData {
  tiles: ForensicsTile[]
  attribution: ForensicsAttribution[]
  runs: ForensicsRun[]
  segments: ForensicsSegment[]
}

/** Structural mirror of prometheus.ts's panel-emission shape — the `host:<hostname>` panel's `data`. */
export interface PrometheusHostPanelData {
  cpuPsiSomePercent: number | null
  memRunwayEtaSeconds: number | null
  memRunwayPercent: number | null
  memPsiFullAvg10Percent: number | null
  buildSliceJobCount: number
  prochot: boolean
  diskRootFreePercent: number | null
}

/** Structural mirror of cluster.ts `ClusterPanelData` — the `cluster` panel's `data`. */
export interface ClusterPanelData {
  debian1: 'online' | 'offline'
  autoscaler: { state: 'hold' | 'pressure' | 'idle'; idle: number; pressure: number }
  buildslot: { running: number; queued: number; p95WaitSeconds: number | null }
}

/** Structural mirror of cluster.ts `AgentsPanelData` — the `agents` panel's `data`. */
export interface AgentsFleetEntry {
  class: string
  count: number
  cpuPercent: number
  slices: string[]
}

export interface AgentsPanelData {
  fleet: AgentsFleetEntry[]
  orphans: number
  totalLive: number
}

/** Structural mirror of botmaster.ts `BotsPanelData` — the `bots` panel's `data`. */
export interface BotPanelRow {
  id: string
  name: string
  project?: string
  runtimeStatus: string
  status: 'live' | 'slow' | 'down' | 'idle'
  statusDetail?: string
  messages24h: number
  errors: number
  cost: number | null
  messagesTotal: number
  costTotal: number | null
  lastActivityAt: string | null
  lastMessageAt: string | null
}

export interface BotsPanelData {
  bots: BotPanelRow[]
  d1LatestAt: string | null
  mirrorLagHours: number | null
}

/** Structural mirror of gates.ts `GatesPanelData` — the `gates` panel's `data`. */
export interface SlopgateRepo {
  repo: string
  debt: number
  trend7d: number
}

export interface GatesPanelData {
  preventOpen: number
  slopgateDebtTotal: number
  slopgateDebtTrend7d: number
  warnignorePending: number
  warnignoreAdds7d: number
  slopgateRepos: SlopgateRepo[]
}

/** Structural mirror of permissions.ts `publish()` — the `permission-gate` panel's `data`. */
export interface PermissionGatePanelData {
  armedUntil: number | null
  armWindowMs: number
  waitMs: number
  pending: number
  maxPending: number
}


