/*
* Copyright (c) 2022 Daniél Kerkmann <daniel@kerkmann.dev>
*
* Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
* the European Commission - subsequent versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* https://joinup.ec.europa.eu/software/page/eupl
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*
* SPDX-License-Identifier: EUPL-1.2
*/

#[macro_use]
extern crate lazy_static;

use actix_web::middleware::Logger;
use actix_web::web::Json;
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
use log::info;

mod types;
mod utils;

use types::*;
use utils::*;

#[get("/oauth2/authorize")]
async fn authorization(
    authorization_request: web::Query<AuthorizationRequest>,
) -> Result<HttpResponse, ApplicationError> {
    let query = serde_url_params::to_string(&authorization_request.0)?;
    let url = String::from("https://id.twitch.tv/oauth2/authorize?") + query.as_str();
    let response = HttpResponse::TemporaryRedirect()
        .insert_header(("Location", url))
        .finish();
    Ok(response)
}

#[post("/oauth2/token")]
async fn token(
    token_request: web::Form<TokenRequest>,
) -> Result<Json<TokenResponse>, ApplicationError> {
    let query = serde_url_params::to_string(&token_request.0)?;
    let url = String::from("https://id.twitch.tv/oauth2/token?") + query.as_str();
    let token_response: TokenResponse = ureq::post(&url).call()?.into_json()?;
    let response = web::Json(token_response);
    Ok(response)
}

#[get("/oauth2/userinfo")]
async fn userinfo(
    userinfo_request: web::Query<UserinfoRequest>,
) -> Result<Json<UserinfoResponse>, ApplicationError> {
    let userinfo_response: UserinfoResponse = ureq::get("https://id.twitch.tv/oauth2/userinfo")
        .set("Content-Type", "application/json")
        .set(
            "Authorization",
            format!("Bearer {}", userinfo_request.0.access_token).as_str(),
        )
        .call()?
        .into_json()?;

    let response = web::Json(userinfo_response);
    Ok(response)
}

async fn not_found() -> impl Responder {
    HttpResponse::TemporaryRedirect()
        .insert_header(("Location", "https://gitlab.com/kerkmann/twitch_oidc_fix"))
        .finish()
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv::dotenv().ok();
    env_logger::init();

    if ENV.default_claims.id_token.email
        || ENV.default_claims.id_token.email_verified
        || ENV.default_claims.userinfo.email
        || ENV.default_claims.userinfo.email_verified
    {
        info!("The claim 'email' or 'email_verified' is enabled, keep in mind to add the scope 'user:read:email'.");
    }

    HttpServer::new(|| {
        let logger = Logger::default();

        App::new()
            .wrap(logger)
            .service(authorization)
            .service(token)
            .service(userinfo)
            .default_service(web::route().to(not_found))
    })
    .bind((ENV.host.clone(), ENV.port))?
    .run()
    .await
}
