## Worker context handling
##
## Reads/writes .worker-ctx.json in worktrees for agent discovery.

import std/[os, json, times, strformat]
import ./types

proc writeContext*(worktree: string, ctx: WorkerContext) =
  ## Write context file to worktree
  let path = worktree / ContextFileName
  try:
    writeFile(path, $ctx.toJson())
  except IOError as e:
    raise newException(IOError, &"writeContext({path}): {e.msg}")

proc loadContextFromPath*(path: string): WorkerContext =
  ## Load and parse context from a specific file path.
  ## Validates the file exists and is not a symlink.
  if not fileExists(path):
    raise newException(IOError, &"Context file not found: {path}")

  # Security: reject symlinks to prevent reading arbitrary files
  if getFileInfo(path).kind == pcLinkToFile:
    raise newException(IOError, &"Context file is a symlink (rejected): {path}")

  try:
    let content = readFile(path)
    let j = parseJson(content)
    return WorkerContext.fromJson(j)
  except JsonParsingError as e:
    raise newException(IOError, &"loadContextFromPath({path}): invalid JSON: {e.msg}")
  except KeyError as e:
    raise newException(IOError, &"loadContextFromPath({path}): missing field: {e.msg}")
  except TimeParseError as e:
    raise newException(IOError, &"loadContextFromPath({path}): invalid date format: {e.msg}")

proc readContext*(worktree: string = ""): WorkerContext =
  ## Read context from worktree. If empty, uses current directory.
  let dir = if worktree != "": worktree else: getCurrentDir()
  let path = dir / ContextFileName
  return loadContextFromPath(path)

proc findContext*(): WorkerContext =
  ## Find context by walking up directory tree
  var dir = getCurrentDir()
  while dir != "" and dir != "/":
    let path = dir / ContextFileName
    if fileExists(path):
      return loadContextFromPath(path)
    dir = parentDir(dir)

  raise newException(IOError, "No .worker-ctx.json found in directory tree")

proc isInWorktree*(): bool =
  ## Check if current directory is inside a worker worktree
  try:
    discard findContext()
    return true
  except IOError:
    return false

proc getTaskId*(): string =
  ## Get task ID from context
  return findContext().taskId

proc createWorkerContext*(taskId, branch, worktree, description: string): WorkerContext =
  ## Create a new context and write to worktree
  result = WorkerContext(
    taskId: taskId,
    branch: branch,
    worktree: worktree,
    createdAt: getTime(),
    description: description
  )
  writeContext(worktree, result)
