use std::path::PathBuf;
use thiserror::Error;

pub type Result<T> = std::result::Result<T, BunbunError>;

#[derive(Error, Debug)]
pub enum BunbunError {
    #[error("I/O error on {path}: {source}")]
    Io {
        path: PathBuf,
        source: std::io::Error,
    },

    #[error("Bad magic bytes in {format} file: {path}")]
    BadMagic {
        format: &'static str,
        path: PathBuf,
    },

    #[error("Unsupported {format} version: {version}")]
    UnsupportedVersion {
        format: &'static str,
        version: String,
    },

    #[error("Malformed {format} header at offset {offset}: {detail}")]
    MalformedHeader {
        format: &'static str,
        offset: usize,
        detail: String,
    },

    #[error("Dimension mismatch: expected {expected}, got {got} ({context})")]
    DimensionMismatch {
        expected: String,
        got: String,
        context: &'static str,
    },

    #[error("Failed to parse {format} record {record}: {detail}")]
    ParseRecord {
        format: &'static str,
        record: usize,
        detail: String,
    },

    #[error("Decompression error ({codec}): {detail}")]
    Decompression {
        codec: &'static str,
        detail: String,
    },

    #[error("Polars error: {0}")]
    Polars(#[from] polars_core::error::PolarsError),
}

impl BunbunError {
    pub fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
        Self::Io {
            path: path.into(),
            source,
        }
    }
}
