'use strict';

/**
 * Path Validator Utility
 *
 * Utility validasi path-aware untuk CLI handler yang menerima input path-like.
 * Mencegah path traversal via `..` atau absolute path keluar dari working directory.
 *
 * Phase 02 dari Security Hardening v1 (Temuan B3).
 *
 * @module lib/utils/path-validator
 */

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

const SAFE_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;

/**
 * Validate nama folder/file/module yang aman digunakan sebagai path component.
 * Hanya memperbolehkan alphanumeric, dash, dan underscore.
 *
 * @param {string} value - Input value dari CLI argument
 * @param {string} fieldName - Nama field untuk konteks error message
 * @returns {string} value yang sudah divalidasi (untuk chaining)
 * @throws {Error} jika value tidak valid (non-string, kosong, atau mengandung
 *                karakter di luar whitelist)
 */
function validateSafeName(value, fieldName) {
    if (typeof value !== 'string' || value.length === 0) {
        throw new Error(`${fieldName} must be a non-empty string`);
    }
    if (!SAFE_NAME_REGEX.test(value)) {
        throw new Error(
            `${fieldName} must contain only alphanumeric, dash, or underscore characters. ` +
            `Got: ${JSON.stringify(value)}`
        );
    }
    return value;
}

/**
 * Validate bahwa resolved targetPath berada di dalam baseDir.
 * Mencegah path traversal via `..` atau absolute path keluar.
 *
 * @param {string} targetPath - Path target (boleh relative atau absolute)
 * @param {string} baseDir - Base directory yang harus mengandung targetPath
 * @returns {string} resolved absolute path
 * @throws {Error} jika resolved path escape dari baseDir
 */
function validatePathWithinBase(targetPath, baseDir) {
    if (typeof targetPath !== 'string' || targetPath.length === 0) {
        throw new Error('targetPath must be a non-empty string');
    }
    if (typeof baseDir !== 'string' || baseDir.length === 0) {
        throw new Error('baseDir must be a non-empty string');
    }

    const baseResolved = path.resolve(baseDir);
    const resolved = path.isAbsolute(targetPath)
        ? path.resolve(targetPath)
        : path.resolve(baseResolved, targetPath);

    if (resolved !== baseResolved && !resolved.startsWith(baseResolved + path.sep)) {
        throw new Error(
            `Path "${targetPath}" escapes from base directory ${baseDir}`
        );
    }
    return resolved;
}

module.exports = { validateSafeName, validatePathWithinBase };
