/// Storage engine error types.
///
/// Replaces the stub `StorageError { message }` from Phase 1.1.
/// All storage backends surface errors through this enum.
#[derive(Debug, thiserror::Error)]
pub enum StorageError {
    /// I/O error from the underlying filesystem or storage engine.
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),
    /// Data corruption detected (checksum mismatch, invalid key encoding, etc.).
    #[error("data corruption: {message}")]
    Corruption { message: String },
    /// The storage engine has been closed and cannot service requests.
    #[error("storage closed")]
    Closed,
    /// A batch write conflicted with a concurrent operation.
    #[error("batch conflict")]
    BatchConflict,
}

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

    #[test]
    fn display_io() {
        let e = StorageError::Io(std::io::Error::new(
            std::io::ErrorKind::NotFound,
            "file not found",
        ));
        assert!(e.to_string().contains("I/O error"));
        assert!(e.to_string().contains("file not found"));
    }

    #[test]
    fn display_corruption() {
        let e = StorageError::Corruption {
            message: "bad checksum".into(),
        };
        assert_eq!(e.to_string(), "data corruption: bad checksum");
    }

    #[test]
    fn display_closed() {
        assert_eq!(StorageError::Closed.to_string(), "storage closed");
    }

    #[test]
    fn display_batch_conflict() {
        assert_eq!(StorageError::BatchConflict.to_string(), "batch conflict");
    }

    #[test]
    fn from_io_error() {
        let io_err = std::io::Error::other("disk full");
        let storage_err: StorageError = io_err.into();
        assert!(matches!(storage_err, StorageError::Io(_)));
    }

    #[test]
    fn source_io() {
        use std::error::Error;
        let e = StorageError::Io(std::io::Error::other("test"));
        assert!(e.source().is_some());
    }

    #[test]
    fn source_corruption_is_none() {
        use std::error::Error;
        let e = StorageError::Corruption {
            message: "test".into(),
        };
        assert!(e.source().is_none());
    }
}
