#!/usr/bin/env node

// NERF Statusline Hook
// Renders a formatted statusline for Claude Code and writes a bridge file
// with context metrics that the context monitor hook consumes.
//
// Bridge file: /tmp/nerf-ctx-{session_id}.json
// Contains: { percent_used, percent_remaining, timestamp }

"use strict";

const fs = require("fs");
const path = require("path");

// --- Constants ---

const STDIN_TIMEOUT_MS = 3000;
const BAR_SEGMENTS = 10;

// Claude Code triggers autocompact at ~83.5% usage, reserving ~16.5% as buffer.
// We account for this so the bar reflects effective capacity, not raw token count.
const AUTOCOMPACT_BUFFER = 0.165;

// ANSI escape helpers
const RESET = "\x1b[0m";
const BOLD = "\x1b[1m";
const DIM = "\x1b[2m";
const BLINK = "\x1b[5m";
const GREEN = "\x1b[32m";
const YELLOW = "\x1b[33m";
const RED = "\x1b[31m";
const ORANGE = "\x1b[38;5;208m";
const GRAY = "\x1b[90m";

// --- Helpers ---

function readStdinWithTimeout(timeoutMs) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      process.stdin.destroy();
      reject(new Error("stdin timeout"));
    }, timeoutMs);

    const chunks = [];
    process.stdin.setEncoding("utf8");
    process.stdin.on("data", (chunk) => chunks.push(chunk));
    process.stdin.on("end", () => {
      clearTimeout(timer);
      resolve(chunks.join(""));
    });
    process.stdin.on("error", (err) => {
      clearTimeout(timer);
      reject(err);
    });
    process.stdin.resume();
  });
}

/**
 * Build a 10-segment context usage bar with color coding.
 *
 * Color thresholds (based on used percentage):
 *   <50%  green   — plenty of room
 *   <65%  yellow  — getting warm
 *   <80%  orange  — running low
 *   >=80% red+blink — near autocompact / exhaustion
 */
function buildContextBar(percentUsed) {
  const filled = Math.round((percentUsed / 100) * BAR_SEGMENTS);
  const empty = BAR_SEGMENTS - filled;

  let color;
  if (percentUsed < 50) {
    color = GREEN;
  } else if (percentUsed < 65) {
    color = YELLOW;
  } else if (percentUsed < 80) {
    color = ORANGE;
  } else {
    color = `${RED}${BLINK}`;
  }

  const filledStr = `${color}${"█".repeat(filled)}${RESET}`;
  const emptyStr = `${DIM}${"░".repeat(empty)}${RESET}`;

  return `${filledStr}${emptyStr}`;
}

/**
 * Write the bridge file that the context monitor hook reads.
 * Contains just the metrics it needs for threshold checks.
 */
function writeBridgeFile(sessionId, percentUsed, percentRemaining) {
  if (!sessionId) return;

  const bridgePath = `/tmp/nerf-ctx-${sessionId}.json`;
  const data = {
    percent_used: percentUsed,
    percent_remaining: percentRemaining,
    timestamp: Date.now(),
  };

  try {
    fs.writeFileSync(bridgePath, JSON.stringify(data), { mode: 0o600 });
  } catch {
    // Silent fail — never block tool execution
  }
}

// --- Main ---

async function main() {
  let raw;
  try {
    raw = await readStdinWithTimeout(STDIN_TIMEOUT_MS);
  } catch {
    process.exit(0);
  }

  let session;
  try {
    session = JSON.parse(raw);
  } catch {
    process.exit(0);
  }

  // Extract fields from Claude Code session data
  // Claude Code passes: model.display_name, workspace.current_dir,
  // session_id, context_window.remaining_percentage
  const model = (session.model && session.model.display_name) || "Claude";
  const cwd = (session.workspace && session.workspace.current_dir) || process.cwd();
  const dirName = path.basename(cwd);
  const sessionId = session.session_id || null;
  const remaining = session.context_window && session.context_window.remaining_percentage;

  // Calculate effective usage accounting for the autocompact buffer.
  // Claude Code reserves ~16.5% for autocompact, so normalize:
  // usable remaining = (remaining - buffer) / (100 - buffer) * 100
  let percentUsed = 0;
  let percentRemaining = 100;
  let ctxDisplay = "";

  if (remaining != null) {
    const usableRemaining = Math.max(
      0,
      ((remaining - AUTOCOMPACT_BUFFER * 100) / (100 - AUTOCOMPACT_BUFFER * 100)) * 100
    );
    percentUsed = Math.max(0, Math.min(100, Math.round(100 - usableRemaining)));
    percentRemaining = Math.max(0, 100 - percentUsed);

    // Write bridge file for the context monitor hook
    writeBridgeFile(sessionId, percentUsed, percentRemaining);

    // Build the context bar
    const bar = buildContextBar(percentUsed);
    ctxDisplay = ` ${DIM}|${RESET} ctx ${bar} ${percentUsed}%`;
  }

  // Format: model | directory | context bar
  const line = `${DIM}${model}${RESET} ${DIM}|${RESET} ${dirName}${ctxDisplay}`;

  process.stdout.write(line + "\n");
}

main().catch(() => process.exit(0));
