'use strict';

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

/**
 * Path containment helpers for install-state-driven file operations.
 *
 * Install-state files are project-local and therefore attacker-controllable
 * (a cloned/forked repo can ship a crafted `.cursor/ecc-install-state.json`).
 * `repair`/`uninstall`/`auto-update` replay recorded operations, so every
 * write/delete destination MUST be confined to the adapter-derived trusted
 * root - never trusted from the state file itself (GHSA-hfpv-w6mp-5g95).
 */

function pathEntryExists(target) {
  try {
    fs.lstatSync(target);
    return true;
  } catch (error) {
    if (error && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) {
      return false;
    }
    throw error;
  }
}

/**
 * Canonicalize a path that may not exist yet: realpath its nearest existing
 * ancestor, then re-append the missing tail. This defeats symlink escapes
 * where an intermediate directory is a symlink pointing out of the root.
 */
function realpathNearestExisting(target) {
  let current = path.resolve(target);
  const tail = [];
  while (!pathEntryExists(current)) {
    const parent = path.dirname(current);
    if (parent === current) {
      break;
    }
    tail.unshift(path.basename(current));
    current = parent;
  }
  const real = fs.realpathSync(current);
  return tail.length > 0 ? path.join(real, ...tail) : real;
}

/**
 * True when `target` resolves to `root` itself or a path beneath it, with
 * symlinks resolved on both sides.
 */
function resolveContainment(target, root) {
  const realRoot = realpathNearestExisting(root);
  const realTarget = realpathNearestExisting(target);
  const relativePath = path.relative(realRoot, realTarget);
  const contained = relativePath === ''
    || (
      relativePath !== '..'
      && !relativePath.startsWith(`..${path.sep}`)
      && !path.isAbsolute(relativePath)
    );
  return {
    contained,
    realRoot,
    realTarget
  };
}

function isWithinRoot(target, root) {
  if (!root) {
    return false;
  }

  try {
    return resolveContainment(target, root).contained;
  } catch {
    return false;
  }
}

/**
 * Fail-closed guard: throw unless `target` is contained within `root`.
 * Returns the canonicalized target path on success.
 */
function assertWithinTrustedRoot(target, root, action = 'write') {
  if (!target || typeof target !== 'string') {
    throw new Error(`Refusing to ${action}: missing destination path.`);
  }
  if (!root) {
    throw new Error(`Refusing to ${action} '${target}': no trusted install root resolved.`);
  }

  let containment;
  try {
    containment = resolveContainment(target, root);
  } catch {
    containment = null;
  }
  if (!containment || !containment.contained) {
    throw new Error(`Refusing to ${action} outside the install root: '${target}' is not within '${root}'.`);
  }
  return containment.realTarget;
}

module.exports = {
  realpathNearestExisting,
  isWithinRoot,
  assertWithinTrustedRoot
};
