use axum::{
    extract::{FromRef, FromRequestParts},
    http::request::Parts,
};
use deadpool_diesel::postgres::{Connection, Pool};
use lettre::SmtpTransport;
use oauth2::basic::BasicClient;

use crate::{app_error::AppError, sessions::PgStore, settings::Settings};

#[derive(Clone)]
pub struct AppState {
    pub db_pool: Pool,
    pub mailer: Mailer,
    pub reqwest_client: reqwest::Client,
    pub oauth_client: BasicClient,
    pub session_store: PgStore,
    pub settings: Settings,
}

#[derive(Clone)]
pub struct Mailer(pub SmtpTransport);

impl FromRef<AppState> for Mailer {
    fn from_ref(state: &AppState) -> Self {
        state.mailer.clone()
    }
}

#[derive(Clone)]
pub struct ReqwestClient(pub reqwest::Client);

impl FromRef<AppState> for ReqwestClient {
    fn from_ref(state: &AppState) -> Self {
        ReqwestClient(state.reqwest_client.clone())
    }
}

pub struct DbConn(pub Connection);

impl FromRequestParts<AppState> for DbConn {
    type Rejection = AppError;

    async fn from_request_parts(_: &mut Parts, state: &AppState) -> Result<Self, Self::Rejection> {
        let conn = state.db_pool.get().await?;
        Ok(Self(conn))
    }
}
