//
// Created by Dan Crosby on 3/29/21.
//

#include "UnitConversions.hpp"

namespace shardok {

using Coords = net::eagle0::shardok::storage::fb::Coords;

constexpr double kDefaultMorale = 50.0;

auto ConvertBattalion(const net::eagle0::common::CommonBattalion &battalion) -> Battalion {
    Battalion shardokBattalion{};

    shardokBattalion.mutate_eagle_battalion_id(battalion.eagle_battalion_id());
    shardokBattalion.mutate_size(battalion.size());
    shardokBattalion.mutate_type(
            static_cast<net::eagle0::shardok::storage::fb::BattalionTypeId>(battalion.type()));
    shardokBattalion.mutate_morale(kDefaultMorale);
    shardokBattalion.mutate_armament(static_cast<float>(battalion.armament()));
    shardokBattalion.mutate_training(static_cast<float>(battalion.training()));

    return shardokBattalion;
}

auto ConvertHero(const net::eagle0::common::CommonHero &hero) -> Hero {
    Hero shardokHero{};

    shardokHero.mutate_eagle_hero_id(hero.eagle_hero_id());
    shardokHero.mutate_is_vip(hero.is_vip());

    shardokHero.mutable_profession_info().mutate_profession(
            static_cast<net::eagle0::shardok::storage::fb::Profession>(hero.profession()));
    shardokHero.mutable_profession_info().mutate_meteor_cast_state(
            net::eagle0::shardok::storage::fb::MultiroundMagicState_NONE);
    shardokHero.mutable_profession_info().mutable_cast_target() = Coords(-1, -1);

    shardokHero.mutable_control_info().mutate_controlled_unit_id(-1);
    shardokHero.mutable_control_info().mutate_controlled_this_round(false);

    shardokHero.mutate_strength(static_cast<int8_t>(hero.strength()));
    shardokHero.mutate_strength_xp(static_cast<int16_t>(hero.strength_xp()));

    shardokHero.mutate_agility(static_cast<int8_t>(hero.agility()));
    shardokHero.mutate_agility_xp(static_cast<int16_t>(hero.agility_xp()));

    shardokHero.mutate_constitution(static_cast<int8_t>(hero.constitution()));
    shardokHero.mutate_constitution_xp(static_cast<int16_t>(hero.constitution_xp()));

    shardokHero.mutate_charisma(static_cast<int8_t>(hero.charisma()));
    shardokHero.mutate_charisma_xp(static_cast<int16_t>(hero.charisma_xp()));

    shardokHero.mutate_wisdom(static_cast<int8_t>(hero.wisdom()));
    shardokHero.mutate_wisdom_xp(static_cast<int16_t>(hero.wisdom_xp()));

    shardokHero.mutate_integrity(static_cast<int8_t>(hero.integrity()));
    shardokHero.mutate_ambition(static_cast<int8_t>(hero.ambition()));
    shardokHero.mutate_gregariousness(static_cast<int8_t>(hero.gregariousness()));
    shardokHero.mutate_bravery(static_cast<int8_t>(hero.bravery()));

    shardokHero.mutate_vigor(static_cast<float>(hero.vigor()));
    shardokHero.mutate_starting_vigor(static_cast<float>(hero.vigor()));

    return shardokHero;
}

auto ConvertUnit(
        const net::eagle0::common::CommonUnit &unit,
        const PlayerId shardokPlayerId,
        const vector<PlayerId> &allPlayerIds) -> Unit {
    Unit shardokUnit{};

    shardokUnit.mutate_player_id(shardokPlayerId);

    // Range check eagle_player_id for int8 conversion
    int32_t eagle_id = unit.eagle_player_id();
    if (eagle_id < -128 || eagle_id > 127) {
        throw std::runtime_error(
                "eagle_player_id " + std::to_string(eagle_id) + " out of int8 range");
    }
    shardokUnit.mutate_eagle_player_id(static_cast<int8_t>(eagle_id));
    shardokUnit.mutate_hidden(false);
    shardokUnit.mutate_fortified(false);
    if (unit.has_hero()) {
        shardokUnit.mutate_has_attached_hero(true);
        shardokUnit.mutable_attached_hero() = ConvertHero(unit.hero());
    } else {
        shardokUnit.mutate_has_attached_hero(false);
    }
    shardokUnit.mutate_commanding_unit_id(-1);
    shardokUnit.mutable_location() = Coords(-1, -1);
    shardokUnit.mutable_battalion() = ConvertBattalion(unit.battalion());
    shardokUnit.mutate_remaining_action_points(0);
    shardokUnit.mutate_stun_rounds_remaining(0);

    for (const PlayerId pid : allPlayerIds) {
        shardokUnit.mutable_opponent_knowledge()->Mutate(
                static_cast<flatbuffers::uoffset_t>(pid),
                0);
    }

    shardokUnit.mutate_has_moved_in_zoc(false);
    shardokUnit.mutate_targeted_unit(-1);
    shardokUnit.mutate_volleys_remaining(0);
    shardokUnit.mutate_food_remaining(static_cast<float>(unit.food()));
    shardokUnit.mutate_can_flee(unit.can_flee());
    shardokUnit.mutate_can_archery(unit.can_archery());
    shardokUnit.mutate_can_start_fire(unit.can_start_fire());

    if (unit.has_starting_position_index()) {
        shardokUnit.mutate_starting_position_index(
                static_cast<int8_t>(unit.starting_position_index().value()));
    } else {
        shardokUnit.mutate_starting_position_index(-1);
    }

    return shardokUnit;
}

}  // namespace shardok