<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Exception;

/**
 * Exception thrown when a path traversal attempt is detected.
 */
final class PathTraversalException extends \RuntimeException {

  /**
   * Constructs a PathTraversalException.
   *
   * @param string $path
   *   The offending path.
   * @param string $reason
   *   Reason the path was rejected.
   */
  public function __construct(
    public readonly string $path,
    string $reason,
  ) {
    parent::__construct(sprintf(
      'Path traversal rejected for "%s": %s',
      $path,
      $reason,
    ));
  }

  /**
   * Creates an exception for directory traversal sequences.
   *
   * @param string $path
   *   The offending path.
   *
   * @return self
   *   New exception instance.
   */
  public static function traversalSequence(string $path): self {
    return new self($path, 'Path contains directory traversal sequences.');
  }

  /**
   * Creates an exception for disallowed stream wrapper.
   *
   * @param string $path
   *   The offending path.
   * @param string $wrapper
   *   The disallowed stream wrapper.
   *
   * @return self
   *   New exception instance.
   */
  public static function disallowedWrapper(string $path, string $wrapper): self {
    return new self($path, sprintf('Stream wrapper "%s://" is not allowed.', $wrapper));
  }

  /**
   * Creates an exception for relative paths that cannot be validated.
   *
   * @param string $path
   *   The offending path.
   *
   * @return self
   *   New exception instance.
   */
  public static function outsideAllowedDirectory(string $path): self {
    return new self($path, 'Path must be an absolute filesystem path or use a supported stream wrapper.');
  }

  /**
   * Creates an exception for null byte injection.
   *
   * @param string $path
   *   The offending path.
   *
   * @return self
   *   New exception instance.
   */
  public static function nullByte(string $path): self {
    return new self($path, 'Path contains null bytes.');
  }

}
