# Copyright 2020-2023 the openage authors. See copying.md for legal info.
#
# pylint: disable=too-many-locals,too-many-statements,invalid-name
#
# TODO:
# pylint: disable=line-too-long

"""
Creates effects and resistances for the Apply*Effect and Resistance
abilities.
"""
from __future__ import annotations
import typing

from ....entity_object.conversion.aoc.genie_unit import GenieUnitLineGroup, \
    GenieBuildingLineGroup
from ....entity_object.conversion.converter_object import RawAPIObject
from ....service.conversion import internal_name_lookups
from ....value_object.conversion.forward_ref import ForwardRef

if typing.TYPE_CHECKING:
    from openage.convert.entity_object.conversion.aoc.genie_unit import GenieGameEntityGroup


class AoCEffectSubprocessor:
    """
    Creates raw API objects for attacks/resistances in AoC.
    """

    @staticmethod
    def get_attack_effects(
        line: GenieGameEntityGroup,
        location_ref: str,
        projectile: int = -1
    ) -> list[ForwardRef]:
        """
        Creates effects that are used for attacking (unit command: 7)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param location_ref: Reference to API object the effects are added to.
        :type location_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        dataset = line.data

        if projectile != 1:
            current_unit = line.get_head_unit()

        else:
            projectile_id = line.get_head_unit()["projectile_id1"].value
            current_unit = dataset.genie_units[projectile_id]

        effects = []

        armor_lookup_dict = internal_name_lookups.get_armor_class_lookups(dataset.game_version)

        # FlatAttributeChangeDecrease
        effect_parent = "engine.effect.discrete.flat_attribute_change.FlatAttributeChange"
        attack_parent = "engine.effect.discrete.flat_attribute_change.type.FlatAttributeChangeDecrease"

        attacks = current_unit["attacks"].value

        for attack in attacks.values():
            armor_class = attack["type_id"].value
            attack_amount = attack["amount"].value
            class_name = armor_lookup_dict[armor_class]

            attack_ref = f"{location_ref}.{class_name}"
            attack_raw_api_object = RawAPIObject(attack_ref,
                                                 class_name,
                                                 dataset.nyan_api_objects)
            attack_raw_api_object.add_raw_parent(attack_parent)
            attack_location = ForwardRef(line, location_ref)
            attack_raw_api_object.set_location(attack_location)

            # Type
            type_ref = f"util.attribute_change_type.types.{class_name}"
            change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
            attack_raw_api_object.add_raw_member("type",
                                                 change_type,
                                                 effect_parent)

            # Min value (optional)
            min_value = dataset.pregen_nyan_objects[("effect.discrete.flat_attribute_change."
                                                     "min_damage.AoE2MinChangeAmount")].get_nyan_object()
            attack_raw_api_object.add_raw_member("min_change_value",
                                                 min_value,
                                                 effect_parent)

            # Max value (optional; not added because there is none in AoE2)

            # Change value
            # =================================================================================
            amount_name = f"{location_ref}.{class_name}.ChangeAmount"
            amount_raw_api_object = RawAPIObject(
                amount_name, "ChangeAmount", dataset.nyan_api_objects)
            amount_raw_api_object.add_raw_parent("engine.util.attribute.AttributeAmount")
            amount_location = ForwardRef(line, attack_ref)
            amount_raw_api_object.set_location(amount_location)

            attribute = dataset.pregen_nyan_objects["util.attribute.types.Health"].get_nyan_object()
            amount_raw_api_object.add_raw_member("type",
                                                 attribute,
                                                 "engine.util.attribute.AttributeAmount")
            amount_raw_api_object.add_raw_member("amount",
                                                 attack_amount,
                                                 "engine.util.attribute.AttributeAmount")

            line.add_raw_api_object(amount_raw_api_object)
            # =================================================================================
            amount_forward_ref = ForwardRef(line, amount_name)
            attack_raw_api_object.add_raw_member("change_value",
                                                 amount_forward_ref,
                                                 effect_parent)

            # Ignore protection
            attack_raw_api_object.add_raw_member("ignore_protection",
                                                 [],
                                                 effect_parent)

            line.add_raw_api_object(attack_raw_api_object)
            attack_forward_ref = ForwardRef(line, attack_ref)
            effects.append(attack_forward_ref)

        # Fallback effect
        fallback_effect = dataset.pregen_nyan_objects[("effect.discrete.flat_attribute_change."
                                                       "fallback.AoE2AttackFallback")].get_nyan_object()
        effects.append(fallback_effect)

        return effects

    @staticmethod
    def get_convert_effects(
        line: GenieGameEntityGroup,
        location_ref: str
    ) -> list[ForwardRef]:
        """
        Creates effects that are used for conversion (unit command: 104)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param location_ref: Reference to API object the effects are added to.
        :type location_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        current_unit = line.get_head_unit()
        dataset = line.data

        effects = []

        effect_parent = "engine.effect.discrete.convert.Convert"
        convert_parent = "engine.effect.discrete.convert.type.AoE2Convert"

        unit_commands = current_unit["unit_commands"].value
        for command in unit_commands:
            # Find the Heal command.
            type_id = command["type"].value

            if type_id == 104:
                skip_guaranteed_rounds = -1 * command["work_value1"].value
                skip_protected_rounds = -1 * command["work_value2"].value
                break

        else:
            # Return the empty set
            return effects

        # Unit conversion
        convert_ref = f"{location_ref}.ConvertUnitEffect"
        convert_raw_api_object = RawAPIObject(convert_ref,
                                              "ConvertUnitEffect",
                                              dataset.nyan_api_objects)
        convert_raw_api_object.add_raw_parent(convert_parent)
        convert_location = ForwardRef(line, location_ref)
        convert_raw_api_object.set_location(convert_location)

        # Type
        type_ref = "util.convert_type.types.UnitConvert"
        change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        convert_raw_api_object.add_raw_member("type",
                                              change_type,
                                              effect_parent)

        # Min success (optional; not added because there is none in AoE2)
        # Max success (optional; not added because there is none in AoE2)

        # Chance
        # hardcoded resource
        chance_success = dataset.genie_civs[0]["resources"][182].value / 100
        convert_raw_api_object.add_raw_member("chance_success",
                                              chance_success,
                                              effect_parent)

        # Fail cost (optional; not added because there is none in AoE2)

        # Guaranteed rounds skip
        convert_raw_api_object.add_raw_member("skip_guaranteed_rounds",
                                              skip_guaranteed_rounds,
                                              convert_parent)

        # Protected rounds skip
        convert_raw_api_object.add_raw_member("skip_protected_rounds",
                                              skip_protected_rounds,
                                              convert_parent)

        line.add_raw_api_object(convert_raw_api_object)
        attack_forward_ref = ForwardRef(line, convert_ref)
        effects.append(attack_forward_ref)

        # Building conversion
        convert_ref = f"{location_ref}.ConvertBuildingEffect"
        convert_raw_api_object = RawAPIObject(convert_ref,
                                              "ConvertBuildingUnitEffect",
                                              dataset.nyan_api_objects)
        convert_raw_api_object.add_raw_parent(convert_parent)
        convert_location = ForwardRef(line, location_ref)
        convert_raw_api_object.set_location(convert_location)

        # Type
        type_ref = "util.convert_type.types.BuildingConvert"
        change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        convert_raw_api_object.add_raw_member("type",
                                              change_type,
                                              effect_parent)

        # Min success (optional; not added because there is none in AoE2)
        # Max success (optional; not added because there is none in AoE2)

        # Chance
        # hardcoded resource
        chance_success = dataset.genie_civs[0]["resources"][182].value / 100
        convert_raw_api_object.add_raw_member("chance_success",
                                              chance_success,
                                              effect_parent)

        # Fail cost (optional; not added because there is none in AoE2)

        # Guaranteed rounds skip
        convert_raw_api_object.add_raw_member("skip_guaranteed_rounds",
                                              0,
                                              convert_parent)

        # Protected rounds skip
        convert_raw_api_object.add_raw_member("skip_protected_rounds",
                                              0,
                                              convert_parent)

        line.add_raw_api_object(convert_raw_api_object)
        attack_forward_ref = ForwardRef(line, convert_ref)
        effects.append(attack_forward_ref)

        return effects

    @staticmethod
    def get_heal_effects(
        line: GenieGameEntityGroup,
        location_ref: str
    ) -> list[ForwardRef]:
        """
        Creates effects that are used for healing (unit command: 105)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param location_ref: Reference to API object the effects are added to.
        :type location_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        current_unit = line.get_head_unit()
        dataset = line.data

        effects = []

        effect_parent = "engine.effect.continuous.flat_attribute_change.FlatAttributeChange"
        heal_parent = "engine.effect.continuous.flat_attribute_change.type.FlatAttributeChangeIncrease"

        unit_commands = current_unit["unit_commands"].value
        heal_command = None

        for command in unit_commands:
            # Find the Heal command.
            type_id = command["type"].value

            if type_id == 105:
                heal_command = command
                break

        else:
            # Return the empty set
            return effects

        heal_rate = heal_command["work_value1"].value

        heal_ref = f"{location_ref}.HealEffect"
        heal_raw_api_object = RawAPIObject(heal_ref,
                                           "HealEffect",
                                           dataset.nyan_api_objects)
        heal_raw_api_object.add_raw_parent(heal_parent)
        heal_location = ForwardRef(line, location_ref)
        heal_raw_api_object.set_location(heal_location)

        # Type
        type_ref = "util.attribute_change_type.types.Heal"
        change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        heal_raw_api_object.add_raw_member("type",
                                           change_type,
                                           effect_parent)

        # Min value (optional)
        min_value = dataset.pregen_nyan_objects[("effect.discrete.flat_attribute_change."
                                                 "min_heal.AoE2MinChangeAmount")].get_nyan_object()
        heal_raw_api_object.add_raw_member("min_change_rate",
                                           min_value,
                                           effect_parent)

        # Max value (optional; not added because there is none in AoE2)

        # Change rate
        # =================================================================================
        rate_name = f"{location_ref}.HealEffect.ChangeRate"
        rate_raw_api_object = RawAPIObject(rate_name, "ChangeRate", dataset.nyan_api_objects)
        rate_raw_api_object.add_raw_parent("engine.util.attribute.AttributeRate")
        rate_location = ForwardRef(line, heal_ref)
        rate_raw_api_object.set_location(rate_location)

        attribute = dataset.pregen_nyan_objects["util.attribute.types.Health"].get_nyan_object()
        rate_raw_api_object.add_raw_member("type",
                                           attribute,
                                           "engine.util.attribute.AttributeRate")
        rate_raw_api_object.add_raw_member("rate",
                                           heal_rate,
                                           "engine.util.attribute.AttributeRate")

        line.add_raw_api_object(rate_raw_api_object)
        # =================================================================================
        rate_forward_ref = ForwardRef(line, rate_name)
        heal_raw_api_object.add_raw_member("change_rate",
                                           rate_forward_ref,
                                           effect_parent)

        # Ignore protection
        heal_raw_api_object.add_raw_member("ignore_protection",
                                           [],
                                           effect_parent)

        line.add_raw_api_object(heal_raw_api_object)
        heal_forward_ref = ForwardRef(line, heal_ref)
        effects.append(heal_forward_ref)

        return effects

    @staticmethod
    def get_repair_effects(
        line: GenieGameEntityGroup,
        location_ref: str
    ) -> list[ForwardRef]:
        """
        Creates effects that are used for repairing (unit command: 106)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param location_ref: Reference to API object the effects are added to.
        :type location_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        dataset = line.data
        api_objects = dataset.nyan_api_objects

        name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)

        effects = []

        effect_parent = "engine.effect.continuous.flat_attribute_change.FlatAttributeChange"
        repair_parent = "engine.effect.continuous.flat_attribute_change.type.FlatAttributeChangeIncrease"

        repairable_lines = []
        repairable_lines.extend(dataset.building_lines.values())
        for unit_line in dataset.unit_lines.values():
            if unit_line.is_repairable():
                repairable_lines.append(unit_line)

        for repairable_line in repairable_lines:
            game_entity_name = name_lookup_dict[repairable_line.get_head_unit_id()][0]

            repair_name = f"{game_entity_name}RepairEffect"
            repair_ref = f"{location_ref}.{repair_name}"
            repair_raw_api_object = RawAPIObject(repair_ref,
                                                 repair_name,
                                                 dataset.nyan_api_objects)
            repair_raw_api_object.add_raw_parent(repair_parent)
            repair_location = ForwardRef(line, location_ref)
            repair_raw_api_object.set_location(repair_location)

            line.add_raw_api_object(repair_raw_api_object)

            # Type
            type_ref = f"util.attribute_change_type.types.{game_entity_name}Repair"
            change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
            repair_raw_api_object.add_raw_member("type",
                                                 change_type,
                                                 effect_parent)

            # Min value (optional; not added because buildings don't block repairing)

            # Max value (optional; not added because there is none in AoE2)

            # Change rate
            # =================================================================================
            rate_name = f"{location_ref}.{repair_name}.ChangeRate"
            rate_raw_api_object = RawAPIObject(rate_name, "ChangeRate", dataset.nyan_api_objects)
            rate_raw_api_object.add_raw_parent("engine.util.attribute.AttributeRate")
            rate_location = ForwardRef(line, repair_ref)
            rate_raw_api_object.set_location(rate_location)

            attribute = dataset.pregen_nyan_objects["util.attribute.types.Health"].get_nyan_object()
            rate_raw_api_object.add_raw_member("type",
                                               attribute,
                                               "engine.util.attribute.AttributeRate")

            # Hardcoded repair rate:
            # - Buildings: 750 HP/min = 12.5 HP/s
            # - Ships/Siege: 187.5 HP/min = 3.125 HP/s
            if isinstance(repairable_line, GenieBuildingLineGroup):
                repair_rate = 12.5

            else:
                repair_rate = 3.125

            rate_raw_api_object.add_raw_member("rate",
                                               repair_rate,
                                               "engine.util.attribute.AttributeRate")

            line.add_raw_api_object(rate_raw_api_object)
            # =================================================================================
            rate_forward_ref = ForwardRef(line, rate_name)
            repair_raw_api_object.add_raw_member("change_rate",
                                                 rate_forward_ref,
                                                 effect_parent)

            # Ignore protection
            repair_raw_api_object.add_raw_member("ignore_protection",
                                                 [],
                                                 effect_parent)

            # Repair cost
            property_ref = f"{repair_ref}.Cost"
            property_raw_api_object = RawAPIObject(property_ref,
                                                   "Cost",
                                                   dataset.nyan_api_objects)
            property_raw_api_object.add_raw_parent("engine.effect.property.type.Cost")
            property_location = ForwardRef(line, repair_ref)
            property_raw_api_object.set_location(property_location)

            line.add_raw_api_object(property_raw_api_object)

            cost_ref = f"{game_entity_name}.CreatableGameEntity.{game_entity_name}RepairCost"
            cost_forward_ref = ForwardRef(repairable_line, cost_ref)
            property_raw_api_object.add_raw_member("cost",
                                                   cost_forward_ref,
                                                   "engine.effect.property.type.Cost")

            property_forward_ref = ForwardRef(line, property_ref)
            properties = {
                api_objects["engine.effect.property.type.Cost"]: property_forward_ref
            }

            repair_raw_api_object.add_raw_member("properties",
                                                 properties,
                                                 "engine.effect.Effect")

            repair_forward_ref = ForwardRef(line, repair_ref)
            effects.append(repair_forward_ref)

        return effects

    @staticmethod
    def get_construct_effects(
        line: GenieGameEntityGroup,
        location_ref: str
    ) -> list[ForwardRef]:
        """
        Creates effects that are used for construction (unit command: 101)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param location_ref: Reference to API object the effects are added to.
        :type location_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        dataset = line.data

        name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)

        effects = []

        progress_effect_parent = "engine.effect.continuous.time_relative_progress.TimeRelativeProgressChange"
        progress_construct_parent = "engine.effect.continuous.time_relative_progress.type.TimeRelativeProgressIncrease"
        attr_effect_parent = "engine.effect.continuous.time_relative_attribute.TimeRelativeAttributeChange"
        attr_construct_parent = "engine.effect.continuous.time_relative_attribute.type.TimeRelativeAttributeIncrease"

        constructable_lines = []
        constructable_lines.extend(dataset.building_lines.values())

        for constructable_line in constructable_lines:
            game_entity_name = name_lookup_dict[constructable_line.get_head_unit_id()][0]

            # Construction progress
            contruct_progress_name = f"{game_entity_name}ConstructProgressEffect"
            contruct_progress_ref = f"{location_ref}.{contruct_progress_name}"
            contruct_progress_raw_api_object = RawAPIObject(contruct_progress_ref,
                                                            contruct_progress_name,
                                                            dataset.nyan_api_objects)
            contruct_progress_raw_api_object.add_raw_parent(progress_construct_parent)
            contruct_progress_location = ForwardRef(line, location_ref)
            contruct_progress_raw_api_object.set_location(contruct_progress_location)

            # Type
            type_ref = f"util.construct_type.types.{game_entity_name}Construct"
            change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
            contruct_progress_raw_api_object.add_raw_member("type",
                                                            change_type,
                                                            progress_effect_parent)

            # Total change time
            change_time = constructable_line.get_head_unit()["creation_time"].value
            contruct_progress_raw_api_object.add_raw_member("total_change_time",
                                                            change_time,
                                                            progress_effect_parent)

            line.add_raw_api_object(contruct_progress_raw_api_object)
            contruct_progress_forward_ref = ForwardRef(line, contruct_progress_ref)
            effects.append(contruct_progress_forward_ref)

            # HP increase during construction
            contruct_hp_name = f"{game_entity_name}ConstructHPEffect"
            contruct_hp_ref = f"{location_ref}.{contruct_hp_name}"
            contruct_hp_raw_api_object = RawAPIObject(contruct_hp_ref,
                                                      contruct_hp_name,
                                                      dataset.nyan_api_objects)
            contruct_hp_raw_api_object.add_raw_parent(attr_construct_parent)
            contruct_hp_location = ForwardRef(line, location_ref)
            contruct_hp_raw_api_object.set_location(contruct_hp_location)

            # Type
            type_ref = f"util.attribute_change_type.types.{game_entity_name}Construct"
            change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
            contruct_hp_raw_api_object.add_raw_member("type",
                                                      change_type,
                                                      attr_effect_parent)

            # Total change time
            change_time = constructable_line.get_head_unit()["creation_time"].value
            contruct_hp_raw_api_object.add_raw_member("total_change_time",
                                                      change_time,
                                                      attr_effect_parent)

            # Ignore protection
            contruct_hp_raw_api_object.add_raw_member("ignore_protection",
                                                      [],
                                                      attr_effect_parent)

            line.add_raw_api_object(contruct_hp_raw_api_object)
            contruct_hp_forward_ref = ForwardRef(line, contruct_hp_ref)
            effects.append(contruct_hp_forward_ref)

        return effects

    @staticmethod
    def get_attack_resistances(
        line: GenieGameEntityGroup,
        ability_ref: str
    ) -> list[ForwardRef]:
        """
        Creates resistances that are used for attacking (unit command: 7)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param ability_ref: Reference of the ability raw API object the effects are added to.
        :type ability_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        current_unit = line.get_head_unit()
        dataset = line.data

        armor_lookup_dict = internal_name_lookups.get_armor_class_lookups(dataset.game_version)

        resistances = []

        # FlatAttributeChangeDecrease
        resistance_parent = "engine.resistance.discrete.flat_attribute_change.FlatAttributeChange"
        armor_parent = "engine.resistance.discrete.flat_attribute_change.type.FlatAttributeChangeDecrease"

        if current_unit.has_member("armors"):
            armors = current_unit["armors"].value

        else:
            # TODO: Trees and blast defense
            armors = {}

        for armor in armors.values():
            armor_class = armor["type_id"].value
            armor_amount = armor["amount"].value
            class_name = armor_lookup_dict[armor_class]

            armor_ref = f"{ability_ref}.{class_name}"
            armor_raw_api_object = RawAPIObject(armor_ref, class_name, dataset.nyan_api_objects)
            armor_raw_api_object.add_raw_parent(armor_parent)
            armor_location = ForwardRef(line, ability_ref)
            armor_raw_api_object.set_location(armor_location)

            # Type
            type_ref = f"util.attribute_change_type.types.{class_name}"
            change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
            armor_raw_api_object.add_raw_member("type",
                                                change_type,
                                                resistance_parent)

            # Block value
            # =================================================================================
            amount_name = f"{ability_ref}.{class_name}.BlockAmount"
            amount_raw_api_object = RawAPIObject(
                amount_name, "BlockAmount", dataset.nyan_api_objects)
            amount_raw_api_object.add_raw_parent("engine.util.attribute.AttributeAmount")
            amount_location = ForwardRef(line, armor_ref)
            amount_raw_api_object.set_location(amount_location)

            attribute = dataset.pregen_nyan_objects["util.attribute.types.Health"].get_nyan_object()
            amount_raw_api_object.add_raw_member("type",
                                                 attribute,
                                                 "engine.util.attribute.AttributeAmount")
            amount_raw_api_object.add_raw_member("amount",
                                                 armor_amount,
                                                 "engine.util.attribute.AttributeAmount")

            line.add_raw_api_object(amount_raw_api_object)
            # =================================================================================
            amount_forward_ref = ForwardRef(line, amount_name)
            armor_raw_api_object.add_raw_member("block_value",
                                                amount_forward_ref,
                                                resistance_parent)

            line.add_raw_api_object(armor_raw_api_object)
            armor_forward_ref = ForwardRef(line, armor_ref)
            resistances.append(armor_forward_ref)

        # Fallback effect
        fallback_effect = dataset.pregen_nyan_objects[("resistance.discrete.flat_attribute_change."
                                                       "fallback.AoE2AttackFallback")].get_nyan_object()
        resistances.append(fallback_effect)

        return resistances

    @staticmethod
    def get_convert_resistances(
        line: GenieGameEntityGroup,
        ability_ref: str
    ) -> list[ForwardRef]:
        """
        Creates resistances that are used for conversion (unit command: 104)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param ability_ref: Reference of the ability raw API object the effects are added to.
        :type ability_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        dataset = line.data

        resistances = []

        # AoE2Convert
        resistance_parent = "engine.resistance.discrete.convert.Convert"
        convert_parent = "engine.resistance.discrete.convert.type.AoE2Convert"

        resistance_ref = f"{ability_ref}.Convert"
        resistance_raw_api_object = RawAPIObject(
            resistance_ref, "Convert", dataset.nyan_api_objects)
        resistance_raw_api_object.add_raw_parent(convert_parent)
        resistance_location = ForwardRef(line, ability_ref)
        resistance_raw_api_object.set_location(resistance_location)

        # Type
        if isinstance(line, GenieUnitLineGroup):
            type_ref = "util.convert_type.types.UnitConvert"

        else:
            type_ref = "util.convert_type.types.BuildingConvert"

        convert_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        resistance_raw_api_object.add_raw_member("type",
                                                 convert_type,
                                                 resistance_parent)

        # Chance resist
        # hardcoded resource
        chance_resist = dataset.genie_civs[0]["resources"][77].value / 100
        resistance_raw_api_object.add_raw_member("chance_resist",
                                                 chance_resist,
                                                 resistance_parent)

        if isinstance(line, GenieUnitLineGroup):
            guaranteed_rounds = dataset.genie_civs[0]["resources"][178].value
            protected_rounds = dataset.genie_civs[0]["resources"][179].value

        else:
            guaranteed_rounds = dataset.genie_civs[0]["resources"][180].value
            protected_rounds = dataset.genie_civs[0]["resources"][181].value

        # Guaranteed rounds
        resistance_raw_api_object.add_raw_member("guaranteed_resist_rounds",
                                                 guaranteed_rounds,
                                                 convert_parent)

        # Protected rounds
        resistance_raw_api_object.add_raw_member("protected_rounds",
                                                 protected_rounds,
                                                 convert_parent)

        # Protection recharge
        resistance_raw_api_object.add_raw_member("protection_round_recharge_time",
                                                 0.0,
                                                 convert_parent)

        line.add_raw_api_object(resistance_raw_api_object)
        resistance_forward_ref = ForwardRef(line, resistance_ref)
        resistances.append(resistance_forward_ref)

        return resistances

    @staticmethod
    def get_heal_resistances(
        line: GenieGameEntityGroup,
        ability_ref: str
    ) -> list[ForwardRef]:
        """
        Creates resistances that are used for healing (unit command: 105)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param ability_ref: Reference of the ability raw API object the effects are added to.
        :type ability_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        dataset = line.data

        resistances = []

        resistance_parent = "engine.resistance.continuous.flat_attribute_change.FlatAttributeChange"
        heal_parent = "engine.resistance.continuous.flat_attribute_change.type.FlatAttributeChangeIncrease"

        resistance_ref = f"{ability_ref}.Heal"
        resistance_raw_api_object = RawAPIObject(resistance_ref,
                                                 "Heal",
                                                 dataset.nyan_api_objects)
        resistance_raw_api_object.add_raw_parent(heal_parent)
        resistance_location = ForwardRef(line, ability_ref)
        resistance_raw_api_object.set_location(resistance_location)

        # Type
        type_ref = "util.attribute_change_type.types.Heal"
        change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        resistance_raw_api_object.add_raw_member("type",
                                                 change_type,
                                                 resistance_parent)

        # Block rate
        # =================================================================================
        rate_name = f"{ability_ref}.Heal.BlockRate"
        rate_raw_api_object = RawAPIObject(rate_name, "BlockRate", dataset.nyan_api_objects)
        rate_raw_api_object.add_raw_parent("engine.util.attribute.AttributeRate")
        rate_location = ForwardRef(line, resistance_ref)
        rate_raw_api_object.set_location(rate_location)

        attribute = dataset.pregen_nyan_objects["util.attribute.types.Health"].get_nyan_object()
        rate_raw_api_object.add_raw_member("type",
                                           attribute,
                                           "engine.util.attribute.AttributeRate")
        rate_raw_api_object.add_raw_member("rate",
                                           0.0,
                                           "engine.util.attribute.AttributeRate")

        line.add_raw_api_object(rate_raw_api_object)
        # =================================================================================
        rate_forward_ref = ForwardRef(line, rate_name)
        resistance_raw_api_object.add_raw_member("block_rate",
                                                 rate_forward_ref,
                                                 resistance_parent)

        line.add_raw_api_object(resistance_raw_api_object)
        resistance_forward_ref = ForwardRef(line, resistance_ref)
        resistances.append(resistance_forward_ref)

        return resistances

    @staticmethod
    def get_repair_resistances(
        line: GenieGameEntityGroup,
        ability_ref: str
    ) -> list[ForwardRef]:
        """
        Creates resistances that are used for repairing (unit command: 106)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param ability_ref: Reference of the ability raw API object the effects are added to.
        :type ability_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        current_unit_id = line.get_head_unit_id()
        dataset = line.data
        api_objects = dataset.nyan_api_objects

        resistances = []

        name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)

        game_entity_name = name_lookup_dict[current_unit_id][0]

        resistance_parent = "engine.resistance.continuous.flat_attribute_change.FlatAttributeChange"
        repair_parent = "engine.resistance.continuous.flat_attribute_change.type.FlatAttributeChangeIncrease"

        resistance_ref = f"{ability_ref}.Repair"
        resistance_raw_api_object = RawAPIObject(resistance_ref,
                                                 "Repair",
                                                 dataset.nyan_api_objects)
        resistance_raw_api_object.add_raw_parent(repair_parent)
        resistance_location = ForwardRef(line, ability_ref)
        resistance_raw_api_object.set_location(resistance_location)

        # Type
        type_ref = f"util.attribute_change_type.types.{game_entity_name}Repair"
        change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        resistance_raw_api_object.add_raw_member("type",
                                                 change_type,
                                                 resistance_parent)

        # Block rate
        # =================================================================================
        rate_name = f"{ability_ref}.Repair.BlockRate"
        rate_raw_api_object = RawAPIObject(rate_name, "BlockRate", dataset.nyan_api_objects)
        rate_raw_api_object.add_raw_parent("engine.util.attribute.AttributeRate")
        rate_location = ForwardRef(line, resistance_ref)
        rate_raw_api_object.set_location(rate_location)

        attribute = dataset.pregen_nyan_objects["util.attribute.types.Health"].get_nyan_object()
        rate_raw_api_object.add_raw_member("type",
                                           attribute,
                                           "engine.util.attribute.AttributeRate")
        rate_raw_api_object.add_raw_member("rate",
                                           0.0,
                                           "engine.util.attribute.AttributeRate")

        line.add_raw_api_object(rate_raw_api_object)
        # =================================================================================
        rate_forward_ref = ForwardRef(line, rate_name)
        resistance_raw_api_object.add_raw_member("block_rate",
                                                 rate_forward_ref,
                                                 resistance_parent)

        # Stacking of villager repair HP increase
        construct_property = dataset.pregen_nyan_objects["resistance.property.types.BuildingRepair"].get_nyan_object(
        )
        properties = {
            api_objects["engine.resistance.property.type.Stacked"]: construct_property
        }

        # Add the predefined property
        resistance_raw_api_object.add_raw_member("properties",
                                                 properties,
                                                 "engine.resistance.Resistance")

        line.add_raw_api_object(resistance_raw_api_object)
        resistance_forward_ref = ForwardRef(line, resistance_ref)
        resistances.append(resistance_forward_ref)

        return resistances

    @staticmethod
    def get_construct_resistances(
        line: GenieGameEntityGroup,
        ability_ref: str
    ) -> list[ForwardRef]:
        """
        Creates resistances that are used for constructing (unit command: 101)

        :param line: Unit/Building line that gets the ability.
        :type line: ...dataformat.converter_object.ConverterObjectGroup
        :param ability_ref: Reference of the ability raw API object the effects are added to.
        :type ability_ref: str
        :returns: The forward references for the effects.
        :rtype: list
        """
        current_unit_id = line.get_head_unit_id()
        dataset = line.data
        api_objects = dataset.nyan_api_objects

        resistances = []

        name_lookup_dict = internal_name_lookups.get_entity_lookups(dataset.game_version)

        game_entity_name = name_lookup_dict[current_unit_id][0]

        progress_resistance_parent = "engine.resistance.continuous.time_relative_progress.TimeRelativeProgressChange"
        progress_construct_parent = "engine.resistance.continuous.time_relative_progress.type.TimeRelativeProgressIncrease"
        attr_resistance_parent = "engine.resistance.continuous.time_relative_attribute.TimeRelativeAttributeChange"
        attr_construct_parent = "engine.resistance.continuous.time_relative_attribute.type.TimeRelativeAttributeIncrease"

        # Progress
        resistance_ref = f"{ability_ref}.ConstructProgress"
        resistance_raw_api_object = RawAPIObject(resistance_ref,
                                                 "ConstructProgress",
                                                 dataset.nyan_api_objects)
        resistance_raw_api_object.add_raw_parent(progress_construct_parent)
        resistance_location = ForwardRef(line, ability_ref)
        resistance_raw_api_object.set_location(resistance_location)

        # Type
        type_ref = f"util.construct_type.types.{game_entity_name}Construct"
        change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        resistance_raw_api_object.add_raw_member("type",
                                                 change_type,
                                                 progress_resistance_parent)

        line.add_raw_api_object(resistance_raw_api_object)
        resistance_forward_ref = ForwardRef(line, resistance_ref)
        resistances.append(resistance_forward_ref)

        # Stacking of villager construction times
        construct_property = dataset.pregen_nyan_objects["resistance.property.types.BuildingConstruct"].get_nyan_object(
        )
        properties = {
            api_objects["engine.resistance.property.type.Stacked"]: construct_property
        }

        # Add the predefined property
        resistance_raw_api_object.add_raw_member("properties",
                                                 properties,
                                                 "engine.resistance.Resistance")

        # Health
        resistance_ref = f"{ability_ref}.ConstructHP"
        resistance_raw_api_object = RawAPIObject(resistance_ref,
                                                 "ConstructHP",
                                                 dataset.nyan_api_objects)
        resistance_raw_api_object.add_raw_parent(attr_construct_parent)
        resistance_location = ForwardRef(line, ability_ref)
        resistance_raw_api_object.set_location(resistance_location)

        # Type
        type_ref = f"util.attribute_change_type.types.{game_entity_name}Construct"
        change_type = dataset.pregen_nyan_objects[type_ref].get_nyan_object()
        resistance_raw_api_object.add_raw_member("type",
                                                 change_type,
                                                 attr_resistance_parent)

        # Stacking of villager construction HP increase
        construct_property = dataset.pregen_nyan_objects["resistance.property.types.BuildingConstruct"].get_nyan_object(
        )
        properties = {
            api_objects["engine.resistance.property.type.Stacked"]: construct_property
        }

        # Add the predefined property
        resistance_raw_api_object.add_raw_member("properties",
                                                 properties,
                                                 "engine.resistance.Resistance")

        line.add_raw_api_object(resistance_raw_api_object)
        resistance_forward_ref = ForwardRef(line, resistance_ref)
        resistances.append(resistance_forward_ref)

        return resistances
