import { slash } from '@poppinss/utils';
import { relative, normalize } from 'path';
import { PathTraversalDetectedException } from '../exceptions/index.js';
/**
 * Path prefixer for resolving and prefixing paths for disk drivers
 */
export default class PathPrefixer {
    /**
     * Separator used for dividing path segments is always unix-style forward slash
     */
    separator: '/';
    /**
     * Prefix used for path prefixing. Can be empty string for cloud drivers.
     */
    prefix: string;
    // constructor(prefix?: string);

    constructor(prefix: string = '') {
        /**
         * Separator used for dividing path segments is always unix-style forward slash
         */
        this.separator = '/';
        // strip slashes from the end of the prefix
        this.prefix = prefix.replace(/\/+$/g, '');
        // always end prefix with separator if it is not empty
        if (this.prefix !== '' || prefix === this.separator) {
            this.prefix += this.separator;
        }
    }

    /**
     * Normalize given path to always use `/` as separator and resolve relative paths using `.` and `..`.
     * It also guards against path traversal beyond the root.
     */
    normalizePath(path: string): string {
        // const converted = (0, utils_1.slash)(path);
        const converted = slash(path);
        const parts = [];
        for (const part of converted.split(this.separator)) {
            if (['', '.'].includes(part)) {
                continue;
            }
            if (part === '..') {
                // if we are traversing beyond the root
                if (parts.length === 0) {
                    throw PathTraversalDetectedException.invoke(converted);
                }
                parts.pop();
            } else {
                parts.push(part);
            }
        }
        return parts.join(this.separator);
    }
    /**
     * Ruturns normalized and prefixed location path.
     */
    prefixPath(location: string): string {
        return this.prefix + this.normalizePath(location);
    }
    /**
     * Ruturns normalized and prefixed location path for directory so always ending with slash.
     * Useful for cloud drivers prefix when listitng files.
     */
    prefixDirectoryPath(location: string): string {
        return this.prefixPath(location) + this.separator;
    }
    /**
     * Returns normalized path after stripping the current prefix from it.
     * It is a reverse operation of `prefixPath`.
     */
    stripPrefix(location: string): string {
        // const path = (0, path_1.relative)(this.prefix, (0, utils_1.slash)(location));
        const path = relative(this.prefix, slash(location));
        return this.normalizePath(path);
    }
    /**
     * Returns a new instance of `PathPrefixer` which is using as prefix stripped prefix from path of current `PathPrefixer`.
     */
    withStrippedPrefix(path: string): PathPrefixer {
        return new PathPrefixer(this.stripPrefix(path));
    }
    /**
     * Returns a new instance of `PathPrefixer` which is using as prefix current prefix merged with provided prefix.
     */
    withPrefix(prefix: string): PathPrefixer {
        return new PathPrefixer(this.prefixPath(prefix));
    }
    /**
     * Returns a new instance of `PathPrefixer` which is using as prefix provided normalized path.
     */
    static fromPath(path: string): PathPrefixer {
        // return new this((0, utils_1.slash)((0, path_1.normalize)(path)));
        return new this(slash(normalize(path)));
    }
}
