//! Diagnostics service — server logs, CRDT dump, permission management, and story movement.
//!
//! Extracted from `http/mcp/diagnostics.rs` following the conventions in
//! `docs/architecture/service-modules.md`:
//! - `mod.rs` (this file) — public API, typed [`Error`], orchestration
//! - `io.rs` — the ONLY place that performs side effects (filesystem reads/writes)
//! - `permission.rs` — pure permission-rule generation and wildcard checks

/// Side-effectful diagnostics I/O — log reads, CRDT dumps, filesystem writes.
pub mod io;
/// Pure permission-rule generation and wildcard matching.
pub mod permission;

#[allow(unused_imports)]
pub use io::add_permission_rule;
#[allow(unused_imports)]
pub use permission::generate_permission_rule;
#[allow(unused_imports)]
pub use permission::is_dominated_by_wildcard;

// ── Error type ────────────────────────────────────────────────────────────────

/// Typed errors returned by `service::diagnostics` functions.
///
/// HTTP handlers map these to status codes:
/// - [`Error::NotFound`] → 404 Not Found
/// - [`Error::Validation`] → 400 Bad Request
/// - [`Error::Conflict`] → 409 Conflict
/// - [`Error::Io`] → 500 Internal Server Error
/// - [`Error::UpstreamFailure`] → 500 Internal Server Error
#[allow(dead_code)]
#[derive(Debug)]
pub enum Error {
    /// The requested resource was not found.
    NotFound(String),
    /// A required argument is missing or has an invalid value.
    Validation(String),
    /// The operation cannot proceed due to a conflicting state.
    Conflict(String),
    /// A filesystem read or write operation failed.
    Io(String),
    /// An upstream dependency returned an unexpected error.
    UpstreamFailure(String),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NotFound(msg) => write!(f, "Not found: {msg}"),
            Self::Validation(msg) => write!(f, "Validation error: {msg}"),
            Self::Conflict(msg) => write!(f, "Conflict: {msg}"),
            Self::Io(msg) => write!(f, "I/O error: {msg}"),
            Self::UpstreamFailure(msg) => write!(f, "Upstream failure: {msg}"),
        }
    }
}

// ── Tests ─────────────────────────────────────────────────────────────────────

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn error_display_not_found() {
        let e = Error::NotFound("log file missing".to_string());
        assert!(e.to_string().contains("Not found"));
    }

    #[test]
    fn error_display_validation() {
        let e = Error::Validation("invalid filter".to_string());
        assert!(e.to_string().contains("Validation error"));
    }

    #[test]
    fn error_display_conflict() {
        let e = Error::Conflict("story in wrong stage".to_string());
        assert!(e.to_string().contains("Conflict"));
    }

    #[test]
    fn error_display_io() {
        let e = Error::Io("settings.json write failed".to_string());
        assert!(e.to_string().contains("I/O error"));
    }

    #[test]
    fn error_display_upstream_failure() {
        let e = Error::UpstreamFailure("rebuild failed".to_string());
        assert!(e.to_string().contains("Upstream failure"));
    }
}
