use serde::Serialize;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum AppError {
    #[error("daemon not running")]
    DaemonNotRunning,

    #[error("daemon already running")]
    DaemonAlreadyRunning,

    #[error("daemon health-check timed out after {0}s")]
    HealthCheckTimeout(u64),

    #[error("could not locate mycelium sidecar binary (looked for {0:?})")]
    SidecarNotFound(Vec<std::path::PathBuf>),

    #[error("sidecar exited unexpectedly: {0}")]
    SidecarExited(String),

    #[error("pkexec authentication was cancelled or failed")]
    ElevationCancelled,

    #[error("io error: {0}")]
    Io(#[from] std::io::Error),

    #[error("http error: {0}")]
    Http(#[from] reqwest::Error),

    #[error("daemon returned status {status}: {body}")]
    DaemonStatus { status: u16, body: String },

    #[error("tauri error: {0}")]
    Tauri(#[from] tauri::Error),

    #[error("tauri path error: {0}")]
    TauriPath(String),

    #[error("invalid argument: {0}")]
    BadInput(String),

    #[error("{0}")]
    Other(String),
}

pub type AppResult<T> = Result<T, AppError>;

// Serialize errors as plain strings for the JS side. invoke() rejects with
// the message; the front-end matches on substring or surfaces it raw.
impl Serialize for AppError {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        s.serialize_str(&self.to_string())
    }
}
