//! Runtime error taxonomy exposed to management layers.

use std::{path::PathBuf, time::Duration};

use thiserror::Error;

use crate::manifest::ServiceKey;

/// Failures from Runtime configuration, sandbox validation, or Actor execution.
#[derive(Debug, Error)]
pub enum RuntimeError {
    /// Service ID or revision is empty.
    #[error("service id and revision must not be empty")]
    InvalidServiceKey,

    /// Manifest identity, world, path, or resource limits are invalid.
    #[error("invalid manifest: {0}")]
    InvalidManifest(String),

    /// Runtime manifest TOML could not be decoded.
    #[error("manifest parse failed: {0}")]
    ManifestParse(#[from] toml::de::Error),

    /// A lifecycle operation addressed an unknown service revision.
    #[error("service revision {0} is not registered")]
    ServiceNotRegistered(ServiceKey),

    /// Registration attempted to overwrite an immutable service revision.
    #[error("service revision {0} is already registered")]
    ServiceAlreadyRegistered(ServiceKey),

    /// Wasmtime rejected the Component before it entered the registry.
    #[error("component compilation failed: {0}")]
    ComponentCompilation(#[source] wasmtime::Error),

    /// The Component imports a WASI or Wasmeld interface outside the allowlist.
    #[error("component imports unsupported capability {0}")]
    UnsupportedImport(String),

    /// A supported capability has no configured Host backend.
    #[error("component requires unavailable capability {0}")]
    CapabilityUnavailable(String),

    /// The shared Wasmtime Engine could not be created.
    #[error("runtime creation failed: {0}")]
    RuntimeCreation(#[source] wasmtime::Error),

    /// The configured compiled-Component cache directory could not be prepared.
    #[error("failed to prepare Component compilation cache {path}: {source}")]
    CacheDirectory {
        /// Requested cache directory.
        path: PathBuf,
        /// Underlying filesystem failure.
        #[source]
        source: std::io::Error,
    },

    /// Wasmtime rejected the persistent cache configuration.
    #[error("invalid Component compilation cache configuration: {0}")]
    CacheConfiguration(#[source] wasmtime::Error),

    /// A Component path from a manifest could not be read.
    #[error("failed to read component artifact {path}: {source}")]
    ArtifactRead {
        /// Manifest-provided artifact path.
        path: String,
        /// Underlying filesystem failure.
        #[source]
        source: std::io::Error,
    },

    /// The operating system refused to create an Actor worker thread.
    #[error("failed to spawn actor thread: {0}")]
    ActorThread(#[source] std::io::Error),

    /// Linking, instantiation, or the Component `init` export failed.
    #[error("actor initialization failed: {0}")]
    ActorInitialization(String),

    /// The Actor is stopped, faulted, starting, or no longer accepting work.
    #[error("actor for {0} is unavailable")]
    ActorUnavailable(ServiceKey),

    /// The bounded Actor mailbox has no capacity for another command.
    #[error("actor mailbox for {0} is full")]
    ActorOverloaded(ServiceKey),

    /// The worker exited before returning a queued response.
    #[error("actor for {0} stopped before returning a result")]
    ActorStopped(ServiceKey),

    /// Resident dispatch was attempted on a passive service Component.
    #[error("service revision {0} does not export the resident actor interface")]
    NotResident(ServiceKey),

    /// A Host event payload exceeds its configured resident or input limit.
    #[error("resident event for {service} exceeds the {limit}-byte payload limit")]
    ResidentEventTooLarge {
        /// Actor revision receiving the event.
        service: ServiceKey,
        /// Maximum accepted bytes.
        limit: usize,
    },

    /// A Component returned more effects than one event is allowed to produce.
    #[error("resident event for {service} returned more than {limit} effects")]
    TooManyResidentEffects {
        /// Actor revision that returned the effect list.
        service: ServiceKey,
        /// Maximum effects accepted per event.
        limit: usize,
    },

    /// A raw Component effect has invalid IDs, payloads, names, or timer values.
    #[error("invalid resident effect: {0}")]
    InvalidResidentEffect(String),

    /// Invocation input exceeds the service manifest limit.
    #[error("input for {service} exceeds the {limit}-byte limit")]
    InputTooLarge {
        /// Actor revision receiving the input.
        service: ServiceKey,
        /// Maximum accepted bytes.
        limit: usize,
    },

    /// Invocation output exceeds the service manifest limit.
    #[error("output for {service} exceeds the {limit}-byte limit")]
    OutputTooLarge {
        /// Actor revision returning the output.
        service: ServiceKey,
        /// Maximum accepted bytes.
        limit: usize,
    },

    /// Queue waiting and Component execution exceeded the end-to-end deadline.
    #[error("actor for {service} exceeded its {deadline:?} execution deadline")]
    DeadlineExceeded {
        /// Actor revision whose command expired.
        service: ServiceKey,
        /// Configured end-to-end command deadline.
        deadline: Duration,
    },

    /// A Wasm trap made the current Actor instance unusable.
    #[error("actor for {service} faulted: {message}")]
    ActorFault {
        /// Faulted Actor revision.
        service: ServiceKey,
        /// Wasmtime trap or call failure detail.
        message: String,
    },

    /// Guest code returned a typed WIT error without trapping the Actor.
    #[error("component returned {kind}: {message}")]
    ComponentError {
        /// Export phase such as `init`, `invoke`, or `resident-event`.
        kind: &'static str,
        /// Guest-provided diagnostic text.
        message: String,
    },

    /// An internal registry or lifecycle mutex was poisoned by a panic.
    #[error("runtime lock was poisoned")]
    LockPoisoned,
}
