use crate::execution::WorkerExecutionResult;
use crate::identity::WorkerId;
use crate::working_directory::WorkingDirectoryDiagnostic;
use std::path::PathBuf;

/// Errors returned by the embedded Runtime API.
#[derive(Debug, thiserror::Error)]
pub enum RuntimeError {
    #[error("runtime is stopped")]
    RuntimeStopped,

    #[error("initial worker input must be user input, got {kind}")]
    InvalidInitialInputKind { kind: String },

    #[error("worker {worker_id} was not found")]
    WorkerNotFound { worker_id: WorkerId },

    #[error("worker {worker_id} has no execution backend: {message}")]
    WorkerExecutionUnavailable {
        worker_id: WorkerId,
        message: String,
    },

    #[error("worker creation has no execution backend: {message}")]
    ExecutionBackendUnavailable { message: String },

    #[error("worker {worker_id} execution {operation:?} returned {outcome:?}: {message}")]
    WorkerExecutionRejected {
        worker_id: WorkerId,
        operation: crate::execution::WorkerExecutionOperation,
        outcome: crate::execution::WorkerExecutionOutcome,
        message: String,
        result: WorkerExecutionResult,
    },

    #[error("limit {requested} exceeds maximum {max}")]
    LimitTooLarge { requested: usize, max: usize },

    #[error("invalid request: {0}")]
    InvalidRequest(String),

    #[error(
        "workspace `{workspace_id}` is owned by Runtime server `{owner_server_id}`, not `{requester_server_id}`"
    )]
    WorkspaceOwnerMismatch {
        workspace_id: String,
        owner_server_id: String,
        requester_server_id: String,
    },

    #[error(transparent)]
    WorkingDirectory(#[from] WorkingDirectoryDiagnostic),

    #[error("config bundle `{bundle_id}` was not found")]
    ConfigBundleMissing { bundle_id: String },

    #[error(
        "config bundle `{bundle_id}` digest mismatch: expected {expected_digest}, got {actual_digest}"
    )]
    ConfigBundleDigestMismatch {
        bundle_id: String,
        expected_digest: String,
        actual_digest: String,
    },

    #[error("invalid profile selector `{profile}` for config bundle {bundle_id:?}: {message}")]
    InvalidProfileSelector {
        profile: String,
        bundle_id: Option<String>,
        message: String,
    },

    #[error(
        "config bundle `{bundle_id}` contains unsupported declaration `{declaration_kind}` named `{name}`"
    )]
    UnsupportedConfigDeclaration {
        bundle_id: String,
        declaration_kind: String,
        name: String,
    },

    #[error("runtime store {operation} failed at {}: {source}", path.display())]
    StoreIo {
        operation: &'static str,
        path: PathBuf,
        #[source]
        source: std::io::Error,
    },

    #[error("runtime store {operation} missing data at {}", path.display())]
    StoreMissing {
        operation: &'static str,
        path: PathBuf,
    },

    #[error("runtime store {operation} found corrupt data at {}: {message}", path.display())]
    StoreCorrupt {
        operation: &'static str,
        path: PathBuf,
        message: String,
    },

    #[error("runtime state lock was poisoned")]
    StatePoisoned,
}
