//! Git domain error types.

use std::fmt;

/// Result type alias for Git operations.
pub type GitResult<T = ()> = Result<T, GitError>;

/// Git domain errors.
#[derive(Debug, Clone)]
pub enum GitError {
    /// Repository is not found or not accessible.
    NotFound(String),
    /// Object not found.
    ObjectNotFound(String),
    /// Reference not found.
    RefNotFound(String),
    /// Invalid reference name.
    InvalidRefName(String),
    /// Invalid object id.
    InvalidOid(String),
    /// Branch already exists.
    BranchExists(String),
    /// Tag already exists.
    TagExists(String),
    /// Branch is protected.
    BranchProtected(String),
    /// Merge conflict.
    MergeConflict(String),
    /// Hook execution failed.
    HookFailed(String),
    /// LFS operation failed.
    LfsError(String),
    /// Config error.
    ConfigError(String),
    /// I/O error.
    IoError(String),
    /// Authentication failed.
    AuthFailed(String),
    /// Permission denied.
    PermissionDenied(String),
    /// Locked resource.
    Locked(String),
    /// Internal error.
    Internal(String),
}

impl fmt::Display for GitError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            GitError::NotFound(s) => write!(f, "not found: {}", s),
            GitError::ObjectNotFound(s) => write!(f, "object not found: {}", s),
            GitError::RefNotFound(s) => write!(f, "ref not found: {}", s),
            GitError::InvalidRefName(s) => write!(f, "invalid ref name: {}", s),
            GitError::InvalidOid(s) => write!(f, "invalid oid: {}", s),
            GitError::BranchExists(s) => write!(f, "branch already exists: {}", s),
            GitError::TagExists(s) => write!(f, "tag already exists: {}", s),
            GitError::BranchProtected(s) => write!(f, "branch is protected: {}", s),
            GitError::MergeConflict(s) => write!(f, "merge conflict: {}", s),
            GitError::HookFailed(s) => write!(f, "hook failed: {}", s),
            GitError::LfsError(s) => write!(f, "lfs error: {}", s),
            GitError::ConfigError(s) => write!(f, "config error: {}", s),
            GitError::IoError(s) => write!(f, "io error: {}", s),
            GitError::AuthFailed(s) => write!(f, "auth failed: {}", s),
            GitError::PermissionDenied(s) => write!(f, "permission denied: {}", s),
            GitError::Locked(s) => write!(f, "locked: {}", s),
            GitError::Internal(s) => write!(f, "internal error: {}", s),
        }
    }
}

impl std::error::Error for GitError {}

impl From<git2::Error> for GitError {
    fn from(e: git2::Error) -> Self {
        match e.code() {
            git2::ErrorCode::NotFound => GitError::NotFound(e.message().to_string()),
            git2::ErrorCode::Exists => GitError::BranchExists(e.message().to_string()),
            git2::ErrorCode::InvalidSpec => GitError::InvalidRefName(e.message().to_string()),
            git2::ErrorCode::MergeConflict => GitError::MergeConflict(e.message().to_string()),
            git2::ErrorCode::Auth => GitError::AuthFailed(e.message().to_string()),
            git2::ErrorCode::Invalid => GitError::InvalidOid(e.message().to_string()),
            git2::ErrorCode::Locked => GitError::Locked(e.message().to_string()),
            _ => GitError::Internal(e.message().to_string()),
        }
    }
}

impl From<std::io::Error> for GitError {
    fn from(e: std::io::Error) -> Self {
        GitError::IoError(e.to_string())
    }
}

impl From<sea_orm::DbErr> for GitError {
    fn from(e: sea_orm::DbErr) -> Self {
        GitError::Internal(format!("db error: {}", e))
    }
}
