import { promises as fs } from 'node:fs';
import path from 'node:path';

import { getAlwaysOnRoot } from './always-on-paths.js';

function normalizeRunId(runId) {
  return typeof runId === 'string'
    ? runId.trim().replace(/[^a-zA-Z0-9._:-]/g, '-')
    : '';
}

function ensureTrailingNewline(value) {
  return value.endsWith('\n') ? value : `${value}\n`;
}

function getAlwaysOnRunsDir(projectRoot) {
  return path.join(getAlwaysOnRoot(projectRoot), 'runs');
}

function getRunLogPath(projectRoot, runId) {
  const safeRunId = normalizeRunId(runId);
  if (!safeRunId) {
    throw new Error('runId is required');
  }
  return path.join(getAlwaysOnRunsDir(projectRoot), `${safeRunId}.log`);
}

function getRunEventsPath(projectRoot, runId) {
  const safeRunId = normalizeRunId(runId);
  if (!safeRunId) {
    throw new Error('runId is required');
  }
  return path.join(getAlwaysOnRunsDir(projectRoot), `${safeRunId}.events.jsonl`);
}

export function formatAlwaysOnPlanLogLine({
  timestamp = new Date().toISOString(),
  level = 'info',
  runId,
  planId,
  phase,
  message,
}) {
  const safeMessage = String(message || '').replace(/\s+/g, ' ').trim();
  return `[AlwaysOnPlanRun] ts=${timestamp} level=${level} runId=${runId} planId=${planId} phase=${phase} message=${JSON.stringify(safeMessage)}`;
}

export async function appendAlwaysOnRunLog(projectRoot, runId, lines) {
  const values = Array.isArray(lines) ? lines : [lines];
  const content = values
    .map((line) => (typeof line === 'string' ? line : String(line ?? '')))
    .filter((line) => line.length > 0)
    .map(ensureTrailingNewline)
    .join('');

  if (!content) {
    return;
  }

  await fs.mkdir(getAlwaysOnRunsDir(projectRoot), { recursive: true });
  await fs.appendFile(getRunLogPath(projectRoot, runId), content, 'utf8');
}

export async function appendAlwaysOnRunLogEvent(projectRoot, runId, event) {
  await fs.mkdir(getAlwaysOnRunsDir(projectRoot), { recursive: true });
  await fs.appendFile(
    getRunEventsPath(projectRoot, runId),
    `${JSON.stringify({
      timestamp: new Date().toISOString(),
      ...event,
      runId,
    })}\n`,
    'utf8',
  );
}