// audit-trail.mjs — Structured JSONL audit trail writer
// Resolves the audit-log path via getPolicyValueWithEnvWarn so the env-var
// LLM_SECURITY_AUDIT_LOG and policy.json key audit.log_path stay in sync,
// with a one-time deprecation warning when both are explicitly set.
// No-op when neither env nor policy provides a path. Zero external dependencies.

import { appendFileSync, writeFileSync, accessSync, constants } from 'node:fs';
import { dirname } from 'node:path';
import { getPolicyValueWithEnvWarn } from './policy-loader.mjs';

let auditPath = null;
let initialized = false;

/**
 * Initialize audit trail. Validates the path is writable on first call.
 * @returns {boolean} true if audit trail is enabled and writable
 */
function initAuditTrail() {
  if (initialized) return auditPath !== null;
  initialized = true;

  // D3 (v7.3.0): env still wins, deprecation warning when policy also set.
  const resolved = getPolicyValueWithEnvWarn(
    'audit', 'log_path', 'LLM_SECURITY_AUDIT_LOG', null
  );
  if (!resolved) return false;

  try {
    // Ensure parent directory exists and is writable
    const dir = dirname(resolved);
    accessSync(dir, constants.W_OK);
    // Touch file if it doesn't exist
    try { accessSync(resolved); } catch { writeFileSync(resolved, ''); }
    auditPath = resolved;
    return true;
  } catch (err) {
    process.stderr.write(`[llm-security] Audit trail path not writable: ${resolved} (${err.message})\n`);
    return false;
  }
}

/**
 * Write a structured audit event as one JSON line.
 * No-op when LLM_SECURITY_AUDIT_LOG is not set.
 *
 * @param {object} event
 * @param {string} event.event_type - e.g. trifecta_warning, injection_detected
 * @param {string} event.severity - critical|high|medium|low|info
 * @param {string} event.source - hook or scanner name
 * @param {object} [event.details] - event-specific payload
 * @param {string[]} [event.owasp] - OWASP categories
 * @param {string} [event.action_taken] - blocked|warned|allowed
 */
export function writeAuditEvent(event) {
  if (!initAuditTrail()) return;

  const entry = {
    timestamp: new Date().toISOString(),
    session_id: String(process.ppid || process.pid),
    event_type: event.event_type || 'unknown',
    severity: event.severity || 'info',
    source: event.source || 'unknown',
    details: event.details || {},
    owasp: event.owasp || [],
    action_taken: event.action_taken || 'warned',
  };

  try {
    appendFileSync(auditPath, JSON.stringify(entry) + '\n');
  } catch (err) {
    process.stderr.write(`[llm-security] Audit trail write failed: ${err.message}\n`);
  }
}

/**
 * Check whether audit trail is enabled (for guard clauses in hooks).
 * @returns {boolean}
 */
export function isAuditEnabled() {
  return initAuditTrail();
}

/**
 * Reset internal state (for testing only).
 */
export function _resetForTest() {
  auditPath = null;
  initialized = false;
}
