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

use crate::app::App;
use crate::res;
use crate::response::{EitherExt, from_err};
use axum::extract::{Json, State};
use axum::response::Response;
use nil_core::continent::{Continent, PublicField};
use nil_payload::request::continent::*;
use nil_payload::response::continent::*;

pub async fn get_public_field(
  State(app): State<App>,
  Json(req): Json<GetPublicFieldRequest>,
) -> Response {
  app
    .continent(req.world, |k| k.field(req.coord).map(PublicField::from))
    .await
    .try_map_left(|field| res!(OK, GetPublicFieldResponse(field)))
    .into_inner()
}

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

  match app.get(req.world) {
    Ok(world) => {
      let result = try {
        let world = world.read().await;
        let continent = world.continent();
        let mut fields = Vec::with_capacity(req.coords.len());

        for coord in req.coords {
          let field = continent.field(coord)?;
          fields.push((coord, PublicField::from(field)));
        }

        fields
      };

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

pub async fn size(State(app): State<App>, Json(req): Json<GetContinentSizeRequest>) -> Response {
  app
    .continent(req.world, Continent::size)
    .await
    .map_left(|size| res!(OK, GetContinentSizeResponse(size)))
    .into_inner()
}
