use actix_web::{web::{self, Json}, Responder, get};

use crate::{AppState, db};

pub(crate) mod schemas;

#[utoipa::path(
    params(),
    responses(
        (status = 200, description = "OK", body = EmpireEthic),
    ),
    security(
        ("api_key" = [])
    ),
)]
#[get("/api/v2/empire_ethics")]
pub(crate) async fn empire_ethics(
    data: web::Data<AppState>
) -> impl Responder {
    let db_data: Vec<db::schemas::EmpireEthic> = sqlx::query_as(
        "SELECT * FROM public.empire_ethics ORDER BY empires_id",
    )
    .fetch_all(&data.db)
    .await.expect("Error Fetching Data from DB");

    let mut parsed_data: Vec<schemas::EmpireEthic> = vec![];

    db_data.iter().for_each(|entry| {
        let new_data = schemas::EmpireEthic {
            empires_id: entry.empire_id,
            empires_group_game_id: entry.empire_game_id,
            ethics_id: entry.ethics_id,
            ethics_fanatic: entry.fanatic
        };

        parsed_data.push(new_data);
    });
    
    Json(parsed_data)
}

#[utoipa::path(
    params(
        schemas::AuthParams
    ),
    responses(
        (status = 200, description = "OK", body = Empire),
    ),
    security(
        ("api_key" = [])
    ),
)]
#[get("/api/v2/empires")]
pub(crate) async fn empires(
    data: web::Data<AppState>,
    params: web::Query<schemas::AuthParams>
) -> impl Responder {
    let params: schemas::AuthParams = params.into_inner();

    let db_data: Vec<db::schemas::Empire> = sqlx::query_as(
        "SELECT * FROM public.empires ORDER BY id",
    )
    .fetch_all(&data.db)
    .await.expect("Error Fetching Data from DB");

    let mut parsed_data: Vec<schemas::Empire> = vec![];

    db_data.iter().for_each(|entry| {
        let mut new_data = schemas::Empire {
            id: entry.id,
            group_id: entry.group_id,
            empire_portrait_group_id: Some(entry.portrait_group_id),
            empire_portrait_id: Some(entry.portrait_id),
            group_game_id: entry.game_id,
            discord_user: None,
            gestalt: Some(entry.gestalt)
        };

        if let Some(auth_token) = params.token.clone() {
            if  auth_token == data.auth_tokens.admin || auth_token == data.auth_tokens.moderator {
                new_data.discord_user = entry.discord_user.clone();
            }
        }

        parsed_data.push(new_data);
    });

    Json(parsed_data)
}

#[utoipa::path(
    params(),
    responses(
        (status = 200, description = "OK", body = Ethic),
    ),
    security(
        ("api_key" = [])
    ),
)]
#[get("/api/v2/ethics")]
pub(crate) async fn ethics(
    data: web::Data<AppState>
) -> impl Responder {
    let db_data: Vec<db::schemas::Ethic> = sqlx::query_as(
        "SELECT * FROM public.ethics ORDER BY id",
    )
    .fetch_all(&data.db)
    .await.expect("Error Fetching Data from DB");

    let mut parsed_data: Vec<schemas::Ethic> = vec![];

    db_data.iter().for_each(|entry| {
        let new_data = schemas::Ethic {
            id: entry.id,
            machine_ethic: entry.machine_ethic,
            name: entry.name.clone()
        };

        parsed_data.push(new_data);
    });
    
    Json(parsed_data)
}

#[utoipa::path(
    params(),
    responses(
        (status = 200, description = "OK", body = GameGroup),
    ),
    security(
        ("api_key" = [])
    ),
)]
#[get("/api/v2/game_groups")]
pub(crate) async fn game_groups(
    data: web::Data<AppState>
) -> impl Responder {
    let db_data: Vec<db::schemas::GameGroup> = sqlx::query_as(
        "SELECT * FROM public.game_groups ORDER BY id",
    )
    .fetch_all(&data.db)
    .await.expect("Error Fetching Data from DB");

    let mut parsed_data: Vec<schemas::GameGroup> = vec![];

    db_data.iter().for_each(|entry| {
        let new_data = schemas::GameGroup {
            game_id: entry.game_id,
            id: entry.id,
            name: entry.name.clone()
        };

        parsed_data.push(new_data);
    });
    
    Json(parsed_data)
}

#[utoipa::path(
    params(),
    responses(
        (status = 200, description = "OK", body = Game),
    ),
    security(
        ("api_key" = [])
    ),
)]
#[get("/api/v2/games")]
pub(crate) async fn games(
    data: web::Data<AppState>
) -> impl Responder {
    let db_data: Vec<db::schemas::Game> = sqlx::query_as(
        "SELECT * FROM public.games ORDER BY id",
    )
    .fetch_all(&data.db)
    .await.expect("Error Fetching Data from DB");

    let mut parsed_data: Vec<schemas::Game> = vec![];

    db_data.iter().for_each(|entry| {
        let new_data = schemas::Game {
            id: entry.id,
            name: entry.name.clone()
        };

        parsed_data.push(new_data);
    });
    
    Json(parsed_data)
}

#[utoipa::path(
    params(),
    responses(
        (status = 200, description = "OK", body = PortraitGroup),
    ),
    security(
        ("api_key" = [])
    ),
)]
#[get("/api/v2/portrait_groups")]
pub(crate) async fn portrait_groups(
    data: web::Data<AppState>
) -> impl Responder {
    let db_data: Vec<db::schemas::PortraitGroup> = sqlx::query_as(
        "SELECT * FROM public.portrait_groups ORDER BY id",
    )
    .fetch_all(&data.db)
    .await.expect("Error Fetching Data from DB");

    let mut parsed_data: Vec<schemas::PortraitGroup> = vec![];

    db_data.iter().for_each(|entry| {
        let new_data = schemas::PortraitGroup {
            id: entry.id,
            name: entry.name.clone()
        };

        parsed_data.push(new_data);
    });
    
    Json(parsed_data)
}

#[utoipa::path(
    params(),
    responses(
        (status = 200, description = "OK", body = Portrait),
    ),
    security(
        ("api_key" = [])
    ),
)]
#[get("/api/v2/portraits")]
pub(crate) async fn portraits(
    data: web::Data<AppState>
) -> impl Responder {
    let db_data: Vec<db::schemas::Portrait> = sqlx::query_as(
        "SELECT * FROM public.portraits ORDER BY id",
    )
    .fetch_all(&data.db)
    .await.expect("Error Fetching Data from DB");

    let mut parsed_data: Vec<schemas::Portrait> = vec![];

    db_data.iter().for_each(|entry| {
        let new_data = schemas::Portrait {
            id: entry.id,
            group_id: entry.group_id,
            hires: entry.hires.clone(),
            lores: Some(entry.lores.clone())
        };

        parsed_data.push(new_data);
    });
    
    Json(parsed_data)
}