use async_session::{MemoryStore};
use axum::{
    extract::{
        Extension, Query
    },
    http::{
        header::{HeaderMap}
    },
    response::{IntoResponse, Redirect},
};
use oauth2::{
    basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId,
    PkceCodeChallenge, RedirectUrl, Scope, TokenUrl,
    ClientSecret, TokenResponse, CsrfToken,
};
use serde::{Deserialize};
use std::{env, collections::HashMap};

use crate::User;
// use crate::COOKIE_NAME;

#[derive(Debug, Deserialize)]
#[allow(dead_code)]
pub struct AuthRequest {
    code: String,
    state: String,
}

pub async fn facebook_auth() -> impl IntoResponse {
    let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256();

    // Generate the authorization URL to which we'll redirect the user.
    let (auth_url, csrf_state) = facebook_oauth_client()
        .authorize_url(CsrfToken::new_random)
        .set_pkce_challenge(pkce_code_challenge)
        .url();

    // Redirect to Facebook's oauth service
    Redirect::to(&auth_url.to_string())
}

pub fn facebook_oauth_client() -> BasicClient {
    let redirect_url = env::var("REDIRECT_URL")
        .unwrap_or_else(|_| "http://localhost:40192/auth/facebook".to_string());
        //.unwrap_or_else(|_| "https://www.jean-marie.ca/auth/facebook".to_string());

    let facebook_client_id = env::var("FACEBOOK_CLIENT_ID").expect("Missing FACEBOOK_CLIENT_ID!");
    let facebook_client_secret = env::var("FACEBOOK_CLIENT_SECRET").expect("Missing FACEBOOK_CLIENT_SECRET!");
    let facebook_auth_url = env::var("FACEBOOK_AUTH_URL").unwrap_or_else(|_| {
        "https://www.facebook.com/v15.0/dialog/oauth".to_string()
    });
    let facebook_token_url = env::var("FACEBOOK_TOKEN_URL")
        .unwrap_or_else(|_| "https://graph.facebook.com/v15.0/oauth/access_token".to_string());

    BasicClient::new(
        ClientId::new(facebook_client_id),
        Some(ClientSecret::new(facebook_client_secret)),
        AuthUrl::new(facebook_auth_url).unwrap(),
        Some(TokenUrl::new(facebook_token_url).unwrap()),
    )
    .set_redirect_uri(RedirectUrl::new(redirect_url).unwrap())
}

pub async fn facebook_authorized(
    Query(query): Query<AuthRequest>,
    Extension(store): Extension<MemoryStore>,
    Extension(oauth_clients): Extension<HashMap::<&str, BasicClient>>,
) -> impl IntoResponse {
     // Check for Facebook client
     if oauth_clients.contains_key("Facebook") {
        // Get Facebook client
        let oauth_client = oauth_clients.get(&"Facebook").unwrap();
    
        // Get an auth token
        let token = oauth_client
            .exchange_code(AuthorizationCode::new(query.code.clone()))
            .request_async(async_http_client)
            .await
            .unwrap();
    
        // Fetch user data from facebook
        let client = reqwest::Client::new();
        let user_data: User = client
            .get("https://graph.facebook.com/v15.0/dialog/oauth")
            .bearer_auth(token.access_token().secret())
            .send()
            .await
            .unwrap()
            .json::<User>()
            .await
            .unwrap();
    
    //     // Create a new session filled with user data
    //     let mut session = Session::new();
    //     session.insert("user", &user_data).unwrap();
    
    //     // Store session and get corresponding cookie
    //     let cookie = store.store_session(session).await.unwrap().unwrap();
    
    //     // Build the cookie
    //     let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie);
    
    //     // Set cookie
        let mut headers = HeaderMap::new();
    //     headers.insert(SET_COOKIE, cookie.parse().unwrap());
    
        (headers, Redirect::to(&"/dashboard"))
    } else {
        let mut headers = HeaderMap::new();
            
        (headers, Redirect::to(&"/"))
    }       
}

