//! Error types for the TUI.

use std::{error::Error as StdError, fmt, io, result::Result as StdResult};

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Json(serde_json::Error),
    /// Protocol parse error with context for display in the UI.
    ProtocolParse {
        /// The underlying JSON parse error message.
        message: String,
        /// A preview of the raw message that failed to parse.
        raw_preview: String,
    },
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Io(e) => write!(f, "IO error: {e}"),
            Self::Json(e) => write!(f, "JSON error: {e}"),
            Self::ProtocolParse {
                message,
                raw_preview,
            } => {
                write!(
                    f,
                    "Protocol error: {message}\n\nRaw message preview:\n{raw_preview}"
                )
            }
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Self::Io(e) => Some(e),
            Self::Json(e) => Some(e),
            Self::ProtocolParse { .. } => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Self::Io(e)
    }
}

impl From<serde_json::Error> for Error {
    fn from(e: serde_json::Error) -> Self {
        Self::Json(e)
    }
}

pub type Result<T> = StdResult<T, Error>;
