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

mod academy;
mod prefecture;
mod stable;
mod workshop;

use crate::continent::{ContinentKey, Coord};
use crate::error::Result;
use crate::infrastructure::prelude::{BuildingId, BuildingLevel};
use crate::world::World;

impl World {
  /// Sets the level of a building.
  ///
  /// Does **NOT** emit any events.
  pub(crate) fn set_building_level(
    &mut self,
    key: impl ContinentKey,
    id: BuildingId,
    level: BuildingLevel,
  ) -> Result<()> {
    self
      .city_mut(key)?
      .infrastructure_mut()
      .building_mut(id)
      .set_level(level);

    Ok(())
  }

  pub fn toggle_building(&mut self, coord: Coord, id: BuildingId, enabled: bool) -> Result<()> {
    self
      .continent
      .city_mut(coord)?
      .infrastructure_mut()
      .building_mut(id)
      .toggle(enabled);

    self.emit_city_updated(coord)?;

    Ok(())
  }
}

#[doc(hidden)]
#[macro_export]
macro_rules! decl_world_recruit_order_fn {
  ($building:ident) => {
    paste::paste! {
      impl World {
        pub fn [<add_ $building:snake _recruit_order>](
          &mut self,
          req: &[<$building RecruitOrderRequest>]
        ) -> Result<()> {
          let player_id = self.city(req.coord)?.player();
          let curr_res = if let Some(id) = &player_id {
            Some(self.player(id)?.resources().clone())
          } else {
            None
          };

          let order = self
            .city_mut(req.coord)?
            .infrastructure_mut()
            .[<add_ $building:snake _recruit_order>](req, curr_res.as_ref())?
            .clone();

          if let Some(id) = player_id {
            let player = self.player_mut(&id)?;
            let resources = player.resources_mut();
            *resources = resources
              .checked_sub(order.resources())
              .ok_or(Error::InsufficientResources)?;

            self.emit_player_updated(id)?;
            self.emit_city_updated(req.coord)?;
          }

          Ok(())
        }

        pub fn [<cancel_ $building:snake _recruit_order>](
          &mut self,
          coord: Coord,
          id: [<$building RecruitOrderId>]
        ) -> Result<()> {
          let city = self.city_mut(coord)?;
          if let Some(order) = city.infrastructure_mut().[<cancel_ $building:snake _recruit_order>](id)
            && let Some(id) = city.player()
          {
            let player = self.player_mut(&id)?;
            let resources = player.resources_mut();
            *resources += order.resources();

            self.emit_player_updated(id)?;
            self.emit_city_updated(coord)?;
          }

          Ok(())
        }
      }
    }
  };
}
