## Shared types for worker coordination
##
## This module defines the core types used across the worker CLI.

import std/[times, json]

type
  WorkerState* = enum
    ## Worker lifecycle states
    ## NOTE: STALE is NOT a state - it's computed from heartbeat age
    wsAssigned = "ASSIGNED"
    wsWorking = "WORKING"
    wsConflicted = "CONFLICTED"
    wsInReview = "IN_REVIEW"
    wsApproved = "APPROVED"
    wsCompleted = "COMPLETED"
    wsFailed = "FAILED"

  WorkerContext* = object
    ## Context for a worker, stored in .worker-ctx.json
    taskId*: string
    branch*: string
    worktree*: string
    createdAt*: Time
    description*: string

  WorkerInfo* = object
    ## Full worker information for status display
    taskId*: string
    state*: WorkerState
    branch*: string
    worktree*: string
    createdAt*: Time
    stateChangedAt*: Time
    lastHeartbeat*: Time
    description*: string

  HeartbeatStatus* = enum
    ## Status reported in heartbeats
    hsIdle = "idle"
    hsWorking = "working"
    hsBlocked = "blocked"

  StaleLevel* = enum
    ## Staleness level based on heartbeat age
    slOk = "ok"
    slWarn = "WARN"
    slStale = "STALE"
    slDead = "DEAD"

  # Errors
  InvalidTransition* = object of CatchableError
  StaleState* = object of CatchableError
  WorkerNotFound* = object of CatchableError
  GitError* = object of CatchableError
  DbError* = object of CatchableError

const
  # Exit codes
  ExitSuccess* = 0
  ExitUsageError* = 2
  ExitInvalidTransition* = 3
  ExitGitError* = 4
  ExitDbError* = 5
  ExitConflict* = 6
  ExitNotFound* = 7

  # Paths
  WorkerStateDir* = ".worker-state"
  BusDbPath* = ".worker-state/bus.db"
  WorktreesDir* = "worktrees"
  ContextFileName* = ".worker-ctx.json"

  # Timing
  HeartbeatIntervalMs* = 10_000  # 10 seconds
  StaleWarnThresholdMs* = 30_000  # 30 seconds
  StaleThresholdMs* = 100_000  # 100 seconds
  DeadThresholdMs* = 300_000  # 5 minutes
  LeaseDurationMs* = 60_000  # 60 seconds
  BusyTimeoutMs* = 5000  # 5 seconds

proc parseState*(s: string): WorkerState =
  ## Parse state string to enum
  case s
  of "ASSIGNED": wsAssigned
  of "WORKING": wsWorking
  of "CONFLICTED": wsConflicted
  of "IN_REVIEW": wsInReview
  of "APPROVED": wsApproved
  of "COMPLETED": wsCompleted
  of "FAILED": wsFailed
  else: raise newException(ValueError, "Unknown state: " & s)

proc epochMs*(): int64 =
  ## Current time as epoch milliseconds
  let t = getTime()
  toUnix(t) * 1000 + nanosecond(t) div 1_000_000

proc toJson*(ctx: WorkerContext): JsonNode =
  ## Serialize context to JSON
  %*{
    "task_id": ctx.taskId,
    "branch": ctx.branch,
    "worktree": ctx.worktree,
    "created_at": $ctx.createdAt,
    "description": ctx.description
  }

const ContextDateFormat* = "yyyy-MM-dd'T'HH:mm:sszzz"

proc fromJson*(T: typedesc[WorkerContext], j: JsonNode): WorkerContext =
  ## Deserialize context from JSON
  let dateStr = j["created_at"].getStr
  var createdAt: Time
  try:
    createdAt = parse(dateStr, ContextDateFormat).toTime()
  except TimeParseError:
    raise newException(TimeParseError,
      "Invalid date format '" & dateStr & "', expected " & ContextDateFormat)
  WorkerContext(
    taskId: j["task_id"].getStr,
    branch: j["branch"].getStr,
    worktree: j["worktree"].getStr,
    createdAt: createdAt,
    description: j{"description"}.getStr
  )
