// Copyright (C) Call of Nil contributors
// SPDX-License-Identifier: AGPL-3.0-only

use crate::app::App;
use crate::middleware::authorization::CurrentPlayer;
use crate::res;
use crate::response::EitherExt;
use axum::extract::{Extension, Json, State};
use axum::response::Response;
use nil_core::ruler::Ruler;
use nil_payload::request::cheat::infrastructure::*;
use nil_payload::response::cheat::infrastructure::*;

pub async fn get_academy_recruit_queue(
  State(app): State<App>,
  Json(req): Json<CheatGetAcademyRecruitQueueRequest>,
) -> Response {
  app
    .world(req.world, |world| {
      world.cheat_get_academy_recruit_queue(req.coord)
    })
    .await
    .try_map_left(|queue| res!(OK, CheatGetAcademyRecruitQueueResponse(queue)))
    .into_inner()
}

pub async fn get_academy_recruit_queues(
  State(app): State<App>,
  Json(req): Json<CheatGetAcademyRecruitQueuesRequest>,
) -> Response {
  if req.coords.is_empty() {
    return res!(OK, CheatGetAcademyRecruitQueuesResponse(Vec::new()));
  }

  app
    .world_blocking(req.world, move |world| {
      world.cheat_get_academy_recruit_queues(&req.coords, req.filter_empty)
    })
    .await
    .try_map_left(|queues| res!(OK, CheatGetAcademyRecruitQueuesResponse(queues)))
    .into_inner()
}

pub async fn get_all_academy_recruit_queues(
  State(app): State<App>,
  Json(req): Json<CheatGetAllAcademyRecruitQueuesRequest>,
) -> Response {
  app
    .world_blocking(req.world, move |world| {
      world.cheat_get_all_academy_recruit_queues(req.filter_empty)
    })
    .await
    .try_map_left(|queues| res!(OK, CheatGetAllAcademyRecruitQueuesResponse(queues)))
    .into_inner()
}

pub async fn get_all_prefecture_build_queues(
  State(app): State<App>,
  Json(req): Json<CheatGetAllPrefectureBuildQueuesRequest>,
) -> Response {
  app
    .world_blocking(req.world, move |world| {
      world.cheat_get_all_prefecture_build_queues(req.filter_empty)
    })
    .await
    .try_map_left(|queues| res!(OK, CheatGetAllPrefectureBuildQueuesResponse(queues)))
    .into_inner()
}

pub async fn get_all_stable_recruit_queues(
  State(app): State<App>,
  Json(req): Json<CheatGetAllStableRecruitQueuesRequest>,
) -> Response {
  app
    .world_blocking(req.world, move |world| {
      world.cheat_get_all_stable_recruit_queues(req.filter_empty)
    })
    .await
    .try_map_left(|queues| res!(OK, CheatGetAllStableRecruitQueuesResponse(queues)))
    .into_inner()
}

pub async fn get_infrastructure(
  State(app): State<App>,
  Json(req): Json<CheatGetInfrastructureRequest>,
) -> Response {
  app
    .world(req.world, |world| world.cheat_get_infrastructure(req.coord))
    .await
    .try_map_left(|infrastructure| res!(OK, CheatGetInfrastructureResponse(infrastructure)))
    .into_inner()
}

pub async fn get_prefecture_build_queue(
  State(app): State<App>,
  Json(req): Json<CheatGetPrefectureBuildQueueRequest>,
) -> Response {
  app
    .world(req.world, |world| {
      world.cheat_get_prefecture_build_queue(req.coord)
    })
    .await
    .try_map_left(|queue| res!(OK, CheatGetPrefectureBuildQueueResponse(queue)))
    .into_inner()
}

pub async fn get_prefecture_build_queues(
  State(app): State<App>,
  Json(req): Json<CheatGetPrefectureBuildQueuesRequest>,
) -> Response {
  if req.coords.is_empty() {
    return res!(OK, CheatGetPrefectureBuildQueuesResponse(Vec::new()));
  }

  app
    .world_blocking(req.world, move |world| {
      world.cheat_get_prefecture_build_queues(&req.coords, req.filter_empty)
    })
    .await
    .try_map_left(|queues| res!(OK, CheatGetPrefectureBuildQueuesResponse(queues)))
    .into_inner()
}

pub async fn get_stable_recruit_queue(
  State(app): State<App>,
  Json(req): Json<CheatGetStableRecruitQueueRequest>,
) -> Response {
  app
    .world(req.world, |world| {
      world.cheat_get_stable_recruit_queue(req.coord)
    })
    .await
    .try_map_left(|queue| res!(OK, CheatGetStableRecruitQueueResponse(queue)))
    .into_inner()
}

pub async fn get_stable_recruit_queues(
  State(app): State<App>,
  Json(req): Json<CheatGetStableRecruitQueuesRequest>,
) -> Response {
  if req.coords.is_empty() {
    return res!(OK, CheatGetStableRecruitQueuesResponse(Vec::new()));
  }

  app
    .world_blocking(req.world, move |world| {
      world.cheat_get_stable_recruit_queues(&req.coords, req.filter_empty)
    })
    .await
    .try_map_left(|queues| res!(OK, CheatGetStableRecruitQueuesResponse(queues)))
    .into_inner()
}

pub async fn get_storage_capacity(
  State(app): State<App>,
  Extension(player): Extension<CurrentPlayer>,
  Json(req): Json<CheatGetStorageCapacityRequest>,
) -> Response {
  let ruler = req
    .ruler
    .unwrap_or_else(|| Ruler::from(player));

  app
    .world(req.world, |world| world.cheat_get_storage_capacity(ruler))
    .await
    .try_map_left(|capacity| res!(OK, CheatGetStorageCapacityResponse(capacity)))
    .into_inner()
}

pub async fn set_building_level(
  State(app): State<App>,
  Json(req): Json<CheatSetBuildingLevelRequest>,
) -> Response {
  app
    .world_mut(req.world, |world| {
      world.cheat_set_building_level(req.coord, req.id, req.level)
    })
    .await
    .try_map_left(|()| res!(OK))
    .into_inner()
}

pub async fn set_max_infrastructure(
  State(app): State<App>,
  Json(req): Json<CheatSetMaxInfrastructureRequest>,
) -> Response {
  app
    .world_mut(req.world, |world| {
      world.cheat_set_max_infrastructure(req.coord)
    })
    .await
    .try_map_left(|()| res!(OK))
    .into_inner()
}
