use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use config::ConfigError;
use opentelemetry_otlp::ExporterBuildError;
use opentelemetry_sdk::error::OTelSdkError;
use secretfile::SecretError;
use tracing_subscriber::util::TryInitError;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error(transparent)]
    Sqlx(#[from] sqlx::Error),
    #[error(transparent)]
    Hyper(#[from] hyper::Error),
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error("page not found")]
    NotFound,
    #[error("Failed to validate steam auth")]
    SteamAuth,
    #[error(transparent)]
    Request(#[from] reqwest::Error),
    #[error(transparent)]
    Xml(#[from] quick_xml::de::DeError),
    #[error(transparent)]
    Session(#[from] async_session::Error),
    #[error(transparent)]
    Setup(#[from] SetupError),
}

#[derive(Debug, thiserror::Error)]
pub enum SetupError {
    #[error("no config file or env provided")]
    NoConfigProvided,
    #[error(transparent)]
    Tracing(#[from] OTelSdkError),
    #[error(transparent)]
    Exporter(#[from] ExporterBuildError),
    #[error(transparent)]
    TracingSubscriber(#[from] TryInitError),
    #[error(transparent)]
    Config(#[from] ConfigError),
    #[error(transparent)]
    Secret(#[from] SecretError),
    #[error("{0}")]
    Other(String),
}

impl Error {
    pub fn status_code(&self) -> StatusCode {
        match self {
            Error::NotFound => StatusCode::NOT_FOUND,
            _ => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }
}

impl IntoResponse for Error {
    fn into_response(self) -> Response {
        let status_code = self.status_code();
        (status_code, format!("{:#}", self)).into_response()
    }
}
