'use strict';

const path = require('node:path');

const BLOCKED_HOST_PATHS = Object.freeze([
  '/',
  '/etc',
  '/private/etc',
  '/var/run',
  '/private/var/run',
  '/System',
  '/Library/Keychains',
  '/Users',
]);

const UNSAFE_NETWORK_MODES = new Set(['host', 'bridge-unrestricted', 'none-disabled']);

function validateSandboxPolicy(policy = {}) {
  const findings = [];
  const enabled = policy.enabled !== false;
  if (!enabled) {
    findings.push(finding('medium', 'sandbox-disabled', 'Sandbox is disabled for this agent run'));
  }

  const networkMode = String(policy.networkMode || policy.network || 'default');
  if (UNSAFE_NETWORK_MODES.has(networkMode)) {
    findings.push(finding('high', 'sandbox-unsafe-network', `Sandbox network mode is unsafe: ${networkMode}`, { networkMode }));
  }

  for (const mount of normalizeMounts(policy.mounts || policy.binds || policy.volumes || [])) {
    const hostPath = normalizePath(mount.hostPath || mount.source || mount.from);
    if (!hostPath) continue;
    const blocked = BLOCKED_HOST_PATHS.find(blockedPath => isSameOrInside(hostPath, blockedPath));
    if (blocked) {
      findings.push(finding('high', 'sandbox-blocked-host-path', 'Sandbox bind mount exposes a blocked host path', {
        hostPath,
        blockedPath: blocked,
      }));
    }
    if (mount.readOnly === false && mount.mode !== 'ro') {
      findings.push(finding('medium', 'sandbox-writeable-mount', 'Sandbox bind mount is writable', { hostPath }));
    }
  }

  return {
    ok: findings.every(item => item.severity !== 'high'),
    findings,
  };
}

function normalizeMounts(mounts = []) {
  if (Array.isArray(mounts)) {
    return mounts.map((mount) => {
      if (typeof mount === 'string') {
        const [hostPath, containerPath, mode] = mount.split(':');
        return { hostPath, containerPath, mode, readOnly: mode === 'ro' };
      }
      return mount || {};
    });
  }
  return Object.entries(mounts || {}).map(([hostPath, value]) => {
    if (typeof value === 'string') return { hostPath, containerPath: value };
    return { hostPath, ...(value || {}) };
  });
}

function normalizePath(value) {
  if (!value) return '';
  return path.resolve(String(value));
}

function isSameOrInside(candidate, parent) {
  const target = normalizePath(candidate);
  const root = normalizePath(parent);
  return target === root || target.startsWith(`${root}${path.sep}`);
}

function finding(severity, code, message, details = {}) {
  return { severity, code, message, details };
}

module.exports = {
  BLOCKED_HOST_PATHS,
  validateSandboxPolicy,
};
