use actix_web::{HttpResponse, ResponseError};
use aws_sdk_dynamodb::error::SdkError;
use serde::Serialize;
use thiserror::Error;

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

#[derive(Debug, Error)]
pub enum Error {
    #[error("db error: {0}")]
    DB(#[from] sqlx::Error),
    #[error("http error: {0}")]
    Http(#[from] reqwest::Error),
    #[error("error getting access token")]
    AccessToken,
    #[error("unauthorized")]
    Unauthorized,
    #[error("jwx error")]
    Jwx(#[from] jsonwebtoken::errors::Error),
    #[error("token expired")]
    TokenExpired,
    #[error("dynamodb error: {0}")]
    DynamoDB(String),
    #[error("item already exists")]
    AlreadyExists,
    #[error("validation failed: {0}")]
    ValidationFailed(String),
    #[error("not found")]
    NotFound,
}

impl<E: std::fmt::Debug> From<SdkError<E>> for Error {
    fn from(err: SdkError<E>) -> Self {
        Error::DynamoDB(format!("{:?}", err))
    }
}

#[derive(Serialize)]
struct ErrorResponse {
    error: String,
}

impl ResponseError for Error {
    fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> {
        match self {
            Error::AccessToken => HttpResponse::BadRequest().finish(),
            Error::Unauthorized => HttpResponse::Unauthorized().finish(),
            Error::TokenExpired => HttpResponse::Unauthorized().json(ErrorResponse {
                error: "token expired".to_string(),
            }),
            Error::AlreadyExists => HttpResponse::BadRequest().json(ErrorResponse {
                error: "item already exists".to_string(),
            }),
            Error::ValidationFailed(msg) => {
                HttpResponse::BadRequest().json(ErrorResponse { error: msg.clone() })
            }
            Error::NotFound => HttpResponse::NotFound().json(ErrorResponse {
                error: "not found".to_string(),
            }),
            _ => HttpResponse::InternalServerError().finish(),
        }
    }
}
