use warp::{self, Filter, reply::Reply};

use crate::{database::DatabaseConnection, scrambler::Scrambler};

pub fn all(
	database_connection: DatabaseConnection,
	access_control_allow_origin: String,
	key_scrambler: Scrambler,
) -> impl warp::Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
	state_load(database_connection.clone(), access_control_allow_origin.clone(), key_scrambler.clone()).or(state_save(
		database_connection,
		access_control_allow_origin,
		key_scrambler,
	))
}

pub fn state_save(
	database_connection: DatabaseConnection,
	access_control_allow_origin: String,
	key_scrambler: Scrambler,
) -> impl warp::Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
	warp::path!("states" / "1.0")
		.and(warp::post().and(warp::body::content_length_limit(1024 * 1024 * 16).and(warp::body::bytes())).then(move |request_body| {
			let key_scrambler = key_scrambler.clone();
			let database_connection = database_connection.clone();
			async move {
				match database_connection.save_state(&key_scrambler, request_body).await {
					Ok(body) => warp::reply::json(&body).into_response(),
					Err((status_code, body)) => warp::reply::with_status(warp::reply::json(&body), status_code).into_response(),
				}
			}
		}))
		.or(warp::options().map(warp::reply))
		.map(move |reply| warp::reply::with_header(reply, "Access-Control-Allow-Origin", access_control_allow_origin.clone()))
		.map(|reply| warp::reply::with_header(reply, "Access-Control-Allow-Headers", "Content-Type"))
		.map(|reply| warp::reply::with_header(reply, "Access-Control-Allow-Methods", "POST"))
}

pub fn state_load(
	database_connection: DatabaseConnection,
	access_control_allow_origin: String,
	key_scrambler: Scrambler,
) -> impl warp::Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
	warp::get()
		.and(warp::path!("states" / "1.0" / String))
		.then(move |state_key: String| {
			let key_scrambler = key_scrambler.clone();
			let database_connection = database_connection.clone();
			async move {
				match database_connection.load_state(&key_scrambler, state_key).await {
					Ok(body) => warp::reply::json(&body).into_response(),
					Err((status_code, body)) => warp::reply::with_status(warp::reply::json(&body), status_code).into_response(),
				}
			}
		})
		.map(move |reply| warp::reply::with_header(reply, "Access-Control-Allow-Origin", access_control_allow_origin.clone()))
		.map(|reply| warp::reply::with_header(reply, "Access-Control-Allow-Headers", "Content-Type"))
		.map(|reply| warp::reply::with_header(reply, "Access-Control-Allow-Methods", "GET"))
}
