use thiserror::Error;

#[derive(Error, Debug)]
pub enum Error {
    #[cfg(any(feature = "mysql", feature = "sqlite"))]
    #[error("Database error: {0}")]
    Database(#[from] sqlx::Error),

    #[cfg(feature = "postgres")]
    #[error("Database error: {0}")]
    Postgres(#[from] tokio_postgres::Error),

    #[error("Pool error: {0}")]
    PoolError(String),

    #[error("Query limit exceeded: {context} on {model} returned {actual_count} records, but limit is {limit}")]
    LimitExceeded {
        limit: usize,
        actual_count: usize,
        context: LimitContext,
        model: String,
    },

    #[error("Write operation \"{operation}\" on {model} requires a transaction")]
    WriteOutsideTransaction { operation: String, model: String },

    #[error("Write operation \"{operation}\" on {model} is not allowed in read-only context")]
    WriteInReadOnlyContext { operation: String, model: String },

    #[error("Configuration error: {0}")]
    Config(String),

    #[error("Column not found: {0}")]
    ColumnNotFound(String),

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

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

    #[error("create_many: row {row_index} has inconsistent columns: expected {expected:?}, got {actual:?}. All rows must have the same set of non-SKIP columns")]
    CreateManyInconsistentColumns {
        row_index: usize,
        expected: Vec<String>,
        actual: Vec<String>,
    },

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

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

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LimitContext {
    Find,
    Relation,
}

impl std::fmt::Display for LimitContext {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            LimitContext::Find => write!(f, "find()"),
            LimitContext::Relation => write!(f, "relation"),
        }
    }
}

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