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

pub mod local;
pub mod remote;

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 itertools::Itertools;
use nil_core::military::army::personnel::ArmyPersonnel;
use nil_core::npc::bot::Bot;
use nil_core::npc::precursor::Precursor;
use nil_core::player::{Player, PlayerStatus};
use nil_core::world::World;
use nil_payload::request::world::*;
use nil_payload::response::world::*;
use std::sync::Arc;

pub async fn get_bots(State(app): State<App>, Json(req): Json<GetWorldBotsRequest>) -> Response {
  app
    .bot_manager(req.world, |bm| bm.bots().map(Bot::id).collect_vec())
    .await
    .map_left(|bots| res!(OK, GetWorldBotsResponse(bots)))
    .into_inner()
}

pub async fn get_config(
  State(app): State<App>,
  Json(req): Json<GetWorldConfigRequest>,
) -> Response {
  app
    .world(req.world, |world| Arc::unwrap_or_clone(world.config()))
    .await
    .map_left(|world| res!(OK, GetWorldConfigResponse(world)))
    .into_inner()
}

pub async fn get_personnel(
  State(app): State<App>,
  Json(req): Json<GetWorldPersonnelRequest>,
) -> Response {
  app
    .military(req.world, |military| {
      military.armies().sum::<ArmyPersonnel>()
    })
    .await
    .map_left(|personnel| res!(OK, GetWorldPersonnelResponse(personnel)))
    .into_inner()
}

pub async fn get_players(
  State(app): State<App>,
  Json(req): Json<GetWorldPlayersRequest>,
) -> Response {
  app
    .player_manager(req.world, |pm| pm.players().map(Player::id).collect_vec())
    .await
    .map_left(|players| res!(OK, GetWorldPlayersResponse(players)))
    .into_inner()
}

pub async fn get_precursors(
  State(app): State<App>,
  Json(req): Json<GetWorldPrecursorsRequest>,
) -> Response {
  app
    .precursor_manager(req.world, |pm| {
      pm.precursors()
        .map(Precursor::id)
        .collect_vec()
    })
    .await
    .map_left(|precursors| res!(OK, GetWorldPrecursorsResponse(precursors)))
    .into_inner()
}

pub async fn get_stats(State(app): State<App>, Json(req): Json<GetWorldStatsRequest>) -> Response {
  app
    .world(req.world, World::stats)
    .await
    .map_left(|stats| res!(OK, GetWorldStatsResponse(stats)))
    .into_inner()
}

pub async fn leave(
  State(app): State<App>,
  Extension(player): Extension<CurrentPlayer>,
  Json(req): Json<LeaveRequest>,
) -> Response {
  if app.server_kind().is_local() {
    app
      .world_mut(req.world, |world| {
        world.set_player_status(&player.0, PlayerStatus::Inactive)
      })
      .await
      .try_map_left(|()| res!(OK))
      .into_inner()
  } else {
    res!(OK)
  }
}
