<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Exception;

/**
 * Exception thrown when module configuration is invalid.
 */
final class InvalidConfigurationException extends \RuntimeException {

  /**
   * Constructs an InvalidConfigurationException.
   *
   * @param string $configKey
   *   The configuration key that is invalid.
   * @param string $reason
   *   Reason why configuration is invalid.
   * @param mixed $value
   *   The invalid value.
   */
  public function __construct(
    public readonly string $configKey,
    string $reason,
    public readonly mixed $value = NULL,
  ) {
    $message = sprintf('Invalid configuration for "%s": %s', $configKey, $reason);
    parent::__construct($message);
  }

  /**
   * Creates an exception for missing required configuration.
   *
   * @param string $configKey
   *   The configuration key.
   *
   * @return self
   *   New exception instance.
   */
  public static function missing(string $configKey): self {
    return new self($configKey, 'Configuration is required but not set.');
  }

  /**
   * Creates an exception for invalid path configuration.
   *
   * @param string $configKey
   *   The configuration key.
   * @param string $path
   *   The invalid path.
   *
   * @return self
   *   New exception instance.
   */
  public static function invalidPath(string $configKey, string $path): self {
    return new self($configKey, 'Path does not exist or is not accessible.', $path);
  }

  /**
   * Creates an exception for invalid value type.
   *
   * @param string $configKey
   *   The configuration key.
   * @param string $expectedType
   *   Expected type.
   * @param mixed $actualValue
   *   The actual value received.
   *
   * @return self
   *   New exception instance.
   */
  public static function invalidType(string $configKey, string $expectedType, mixed $actualValue): self {
    return new self(
      $configKey,
      sprintf('Expected %s, got %s.', $expectedType, gettype($actualValue)),
      $actualValue,
    );
  }

  /**
   * Creates an exception for out of range value.
   *
   * @param string $configKey
   *   The configuration key.
   * @param int|float $value
   *   The invalid value.
   * @param int|float $min
   *   Minimum allowed value.
   * @param int|float $max
   *   Maximum allowed value.
   *
   * @return self
   *   New exception instance.
   */
  public static function outOfRange(
    string $configKey,
    int|float $value,
    int|float $min,
    int|float $max,
  ): self {
    return new self(
      $configKey,
      sprintf('Value must be between %s and %s.', $min, $max),
      $value,
    );
  }

  /**
   * Creates an exception for missing formatter configuration.
   *
   * @param string $entityType
   *   Entity type.
   * @param string $bundle
   *   Bundle name.
   *
   * @return self
   *   New exception instance.
   */
  public static function missingFormatterConfiguration(string $entityType, string $bundle): self {
    return new self(
      'formatter_configuration',
      sprintf('No formatter configuration found for %s.%s.', $entityType, $bundle),
    );
  }

  /**
   * Creates an exception from a simple message string.
   *
   * @param string $message
   *   The error message.
   * @param string $configKey
   *   Optional configuration key (defaults to 'general').
   *
   * @return self
   *   New exception instance.
   */
  public static function fromMessage(string $message, string $configKey = 'general'): self {
    return new self($configKey, $message);
  }

}
