use thiserror::Error;
use tonic::{
    Code, Status,
    metadata::errors::{InvalidMetadataKey, InvalidMetadataValue},
};

#[derive(Debug, Error)]
pub enum GrpcAdapterError {
    #[error("invalid descriptor set encoding")]
    InvalidDescriptorEncoding,
    #[error("invalid descriptor set")]
    InvalidDescriptorSet,
    #[error("invalid descriptor pool")]
    InvalidDescriptorPool,
    #[error("service {service} was not found in descriptor set")]
    ServiceNotFound { service: String },
    #[error("method {method} was not found in service {service}")]
    MethodNotFound { service: String, method: String },
    #[error("grpc method path is invalid for service {service} and method {method}")]
    InvalidMethodPath { service: String, method: String },
    #[error("grpc method {service}/{method} is not supported for unary execution")]
    UnsupportedMethodKind { service: String, method: String },
    #[error("grpc method {service}/{method} does not support server-stream execution")]
    UnsupportedStreamingMethodKind { service: String, method: String },
    #[error("invalid metadata key {key}")]
    InvalidMetadataKey {
        key: String,
        #[source]
        source: InvalidMetadataKey,
    },
    #[error("invalid metadata value for key {key}")]
    InvalidMetadataValue {
        key: String,
        #[source]
        source: InvalidMetadataValue,
    },
    #[error("transport endpoint is invalid")]
    InvalidEndpoint(#[from] tonic::transport::Error),
    #[error("stream collection window expired before grpc stream completed")]
    WindowExpired,
    #[error("grpc status {code}: {message}")]
    Status { code: Code, message: String },
}

impl From<Status> for GrpcAdapterError {
    fn from(value: Status) -> Self {
        Self::Status {
            code: value.code(),
            message: value.message().to_owned(),
        }
    }
}
