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

use crate::app::App;
use crate::middleware::authorization::CurrentPlayer;
use crate::response::from_err;
use crate::{bail_if_city_is_not_owned_by, bail_if_player_is_not_pending, res};
use axum::extract::{Extension, Json, State};
use axum::response::Response;
use nil_core::infrastructure::building::r#impl::prefecture::build_catalog::PrefectureBuildCatalog;
use nil_payload::request::infrastructure::prefecture::*;
use nil_payload::response::infrastructure::prefecture::*;

pub async fn add_build_order(
  State(app): State<App>,
  Extension(player): Extension<CurrentPlayer>,
  Json(req): Json<AddPrefectureBuildOrderRequest>,
) -> Response {
  match app.get(req.world) {
    Ok(world) => {
      let result = try {
        let mut world = world.write().await;
        bail_if_player_is_not_pending!(world, &player.0);
        bail_if_city_is_not_owned_by!(world, &player.0, req.request.coord);
        world.add_prefecture_build_order(&req.request)?;
      };

      result
        .map(|()| res!(OK))
        .unwrap_or_else(from_err)
    }
    Err(err) => from_err(err),
  }
}

pub async fn cancel_build_order(
  State(app): State<App>,
  Extension(player): Extension<CurrentPlayer>,
  Json(req): Json<CancelPrefectureBuildOrderRequest>,
) -> Response {
  match app.get(req.world) {
    Ok(world) => {
      let result = try {
        let mut world = world.write().await;
        bail_if_player_is_not_pending!(world, &player.0);
        bail_if_city_is_not_owned_by!(world, &player.0, req.coord);
        world.cancel_prefecture_build_order(req.coord)?;
      };

      result
        .map(|()| res!(OK))
        .unwrap_or_else(from_err)
    }
    Err(err) => from_err(err),
  }
}

pub async fn get_build_catalog(
  State(app): State<App>,
  Extension(player): Extension<CurrentPlayer>,
  Json(req): Json<GetPrefectureBuildCatalogRequest>,
) -> Response {
  match app.get(req.world) {
    Ok(world) => {
      let result = try {
        let world = world.read().await;
        bail_if_city_is_not_owned_by!(world, &player.0, req.coord);
        let infra = world.city(req.coord)?.infrastructure();
        let stats = world.stats().infrastructure();
        PrefectureBuildCatalog::new(infra, &stats)?
      };

      result
        .map(|catalog| res!(OK, GetPrefectureBuildCatalogResponse(catalog)))
        .unwrap_or_else(from_err)
    }
    Err(err) => from_err(err),
  }
}
