from __future__ import annotations

from typing import Dict

from .attributes import Attribute
from .diagram import Diagram
from .diagram_element import DiagramElement
from .entity import Entity
from .input_model import Input
from .links import Link
from .mechanics import Mechanic


def create_sheep_wolf_diagram() -> Diagram:
    """
    Construct the IMR diagram for the Sheep & Wolves example.
    """

    nodes: Dict[str, DiagramElement] = {}

    # --- Input nodes -------------------------------------------------------

    input_wasd = Input(
        id="input_wasd",
        degree_of_freedom=2.0,
    )
    nodes[input_wasd.id] = input_wasd

    input_click = Input(
        id="input_click",
        degree_of_freedom=2.5,
    )
    nodes[input_click.id] = input_click

    input_mouse_wheel = Input(
        id="input_mouse_wheel",
        degree_of_freedom=1.0,
    )
    nodes[input_mouse_wheel.id] = input_mouse_wheel

    input_keys_1_4 = Input(
        id="input_keys_1_4",
        degree_of_freedom=1.0,
    )
    nodes[input_keys_1_4.id] = input_keys_1_4

    # --- Entity nodes (resources) ------------------------------------------

    stock_player = Entity(
        id="stock_player",
        magnitude_order=1.0,
        is_target=True,
    )
    nodes[stock_player.id] = stock_player

    stock_coins = Entity(
        id="stock_coins",
        magnitude_order=3,
    )
    nodes[stock_coins.id] = stock_coins

    stock_bell = Entity(
        id="stock_bell",
    )
    nodes[stock_bell.id] = stock_bell

    stock_stick = Entity(
        id="stock_stick",
    )
    nodes[stock_stick.id] = stock_stick

    stock_sheep = Entity(
        id="stock_sheep",
        magnitude_order=2,
        is_target=True,
    )
    nodes[stock_sheep.id] = stock_sheep

    stock_pastures = Entity(
        id="stock_pastures",
    )
    nodes[stock_pastures.id] = stock_pastures

    stock_grazing_points = Entity(
        id="stock_grazing_points",
    )
    nodes[stock_grazing_points.id] = stock_grazing_points

    stock_rifle = Entity(
        id="stock_rifle",
    )
    nodes[stock_rifle.id] = stock_rifle

    stock_projectiles = Entity(
        id="stock_projectiles",
        magnitude_order=1.0,
    )
    nodes[stock_projectiles.id] = stock_projectiles

    stock_wolves = Entity(
        id="stock_wolves",
        magnitude_order=1.0,
        is_target=True,
    )
    nodes[stock_wolves.id] = stock_wolves

    stock_scenario_section = Entity(
        id="stock_scenario_section",
    )
    nodes[stock_scenario_section.id] = stock_scenario_section

    stock_current_level = Entity(
        id="stock_current_level",
    )
    nodes[stock_current_level.id] = stock_current_level

    stock_time_passed = Entity(
        id="stock_time_passed",
    )
    nodes[stock_time_passed.id] = stock_time_passed

    stock_available_items = Entity(
        id="stock_available_items",
        magnitude_order=1.0,
        is_target=True,
    )
    nodes[stock_available_items.id] = stock_available_items

    stock_environmental_obstacles = Entity(
        id="stock_environmental_obstacles",
        magnitude_order=1.0,
    )
    nodes[stock_environmental_obstacles.id] = stock_environmental_obstacles

    # --- Attribute-like nodes (as entities without stock) ------------------

    attr_player_position = Attribute(
        id="attr_player_position",
    )
    nodes[attr_player_position.id] = attr_player_position

    attr_sheep_position = Attribute(
        id="attr_sheep_position",
    )
    nodes[attr_sheep_position.id] = attr_sheep_position

    attr_pos_cursor = Attribute(
        id="attr_pos_cursor",
    )
    nodes[attr_pos_cursor.id] = attr_pos_cursor

    attr_radius = Attribute(
        id="attr_radius",
    )
    nodes[attr_radius.id] = attr_radius

    attr_sheep_state = Attribute(
        id="attr_sheep_state",
    )
    nodes[attr_sheep_state.id] = attr_sheep_state

    attr_wolf_state = Attribute(
        id="attr_wolf_state",
    )
    nodes[attr_wolf_state.id] = attr_wolf_state

    attr_cooldown = Attribute(
        id="attr_cooldown",
    )
    nodes[attr_cooldown.id] = attr_cooldown

    attr_projectile_transform = Attribute(
        id="attr_projectile_transform",
    )
    nodes[attr_projectile_transform.id] = attr_projectile_transform

    attr_wolf_transform = Attribute(
        id="attr_wolf_transform",
    )
    nodes[attr_wolf_transform.id] = attr_wolf_transform

    attr_pasture_pp = Attribute(
        id="attr_pasture_pp",
    )
    nodes[attr_pasture_pp.id] = attr_pasture_pp

    attr_pasture_transform = Attribute(
        id="attr_pasture_transform",
    )
    nodes[attr_pasture_transform.id] = attr_pasture_transform

    attr_is_equipped = Attribute(
        id="attr_is_equipped",
    )
    nodes[attr_is_equipped.id] = attr_is_equipped

    # --- Mechanic nodes ----------------------------------------------------

    mech_movement = Mechanic(
        id="mech_movement",
    )
    nodes[mech_movement.id] = mech_movement

    mech_item_switch = Mechanic(
        id="mech_item_switch",
    )
    nodes[mech_item_switch.id] = mech_item_switch

    mech_call = Mechanic(
        id="mech_call",
    )
    nodes[mech_call.id] = mech_call

    mech_sound = Mechanic(
        id="mech_sound",
    )
    nodes[mech_sound.id] = mech_sound

    mech_buy_items = Mechanic(
        id="mech_buy_items",
    )
    nodes[mech_buy_items.id] = mech_buy_items

    mech_buy_sheep = Mechanic(
        id="mech_buy_sheep",
    )
    nodes[mech_buy_sheep.id] = mech_buy_sheep

    mech_conversion = Mechanic(
        id="mech_conversion",
    )
    nodes[mech_conversion.id] = mech_conversion

    mech_graze = Mechanic(
        id="mech_graze",
    )
    nodes[mech_graze.id] = mech_graze

    mech_sheep_automation = Mechanic(
        id="mech_sheep_automation",
    )
    nodes[mech_sheep_automation.id] = mech_sheep_automation

    mech_fall = Mechanic(
        id="mech_fall",
    )
    nodes[mech_fall.id] = mech_fall

    mech_fire = Mechanic(
        id="mech_fire",
    )
    nodes[mech_fire.id] = mech_fire

    mech_combat = Mechanic(
        id="mech_combat",
    )
    nodes[mech_combat.id] = mech_combat

    mech_impact = Mechanic(
        id="mech_impact",
    )
    nodes[mech_impact.id] = mech_impact

    mech_wolf_spawn = Mechanic(
        id="mech_wolf_spawn",
    )
    nodes[mech_wolf_spawn.id] = mech_wolf_spawn

    # --- Attach links per node ---------------------------------------------

    # Inputs
    input_wasd.links = [
        Link(
            id="inf_input_wasd_movement",
            target=mech_movement,
        ),
    ]

    input_click.links = [
        Link(
            id="inf_input_click_pos",
            target=attr_pos_cursor,
        ),
    ]

    input_mouse_wheel.links = [
        Link(
            id="inf_mouse_wheel_item_switch",
            target=mech_item_switch,
        ),
    ]

    input_keys_1_4.links = [
        Link(
            id="inf_keys_1_4_item_switch",
            target=mech_item_switch,
        ),
    ]

    # Resource entities → attribute-like entities / resources
    stock_player.links = [
        Link(
            id="bel_player_position",
            target=attr_player_position,
        ),
    ]

    stock_stick.links = [
        Link(
            id="bel_stick_radius",
            target=attr_radius,
        ),
        Link(
            id="inf_stick_call",
            target=mech_call,
        ),
    ]

    stock_sheep.links = [
        Link(
            id="bel_sheep_position",
            target=attr_sheep_position,
        ),
        Link(
            id="bel_sheep_state",
            target=attr_sheep_state,
        ),
        Link(
            id="inf_sheep_graze",
            target=mech_graze,
        ),
        Link(
            id="inf_sheep_sheep_automation",
            target=mech_sheep_automation,
        ),
        Link(
            id="inf_sheep_combat",
            target=mech_combat,
        ),
    ]

    stock_pastures.links = [
        Link(
            id="bel_pastures_pasture_pp",
            target=attr_pasture_pp,
        ),
        Link(
            id="bel_pastures_transform",
            target=attr_pasture_transform,
        ),
        Link(
            id="inf_pastures_graze",
            target=mech_graze,
        ),
        Link(
            id="inf_pastures_sheep_automation",
            target=mech_sheep_automation,
        ),
    ]

    stock_available_items.links = [
        Link(
            id="bel_available_items_is_equipped",
            target=attr_is_equipped,
        ),
        Link(
            id="gen_available_items_bell",
            target=stock_bell,
        ),
        Link(
            id="gen_available_items_stick",
            target=stock_stick,
        ),
        Link(
            id="gen_available_items_rifle",
            target=stock_rifle,
        ),
    ]

    stock_projectiles.links = [
        Link(
            id="bel_projectiles_transform",
            target=attr_projectile_transform,
        ),
        Link(
            id="inf_projectiles_impact",
            target=mech_impact,
        ),
    ]

    stock_wolves.links = [
        Link(
            id="bel_wolves_transform",
            target=attr_wolf_transform,
        ),
        Link(
            id="bel_wolves_state",
            target=attr_wolf_state,
        ),
        Link(
            id="inf_wolves_combat",
            target=mech_combat,
        ),
    ]

    stock_grazing_points.links = [
        Link(
            id="inf_conversion_grazing_points",
            target=mech_conversion,
        ),
    ]

    stock_coins.links = [
        Link(
            id="inf_coins_buy_items",
            target=mech_buy_items,
        ),
        Link(
            id="inf_coins_buy_sheep",
            target=mech_buy_sheep,
        ),
    ]

    stock_environmental_obstacles.links = [
        Link(
            id="inf_sheep_automation_obstacles",
            target=mech_sheep_automation,
        ),
        Link(
            id="inf_obstacles_fall",
            target=mech_fall,
        ),
    ]

    stock_bell.links = [
        Link(
            id="inf_bell_sound",
            target=mech_sound,
        ),
    ]

    stock_rifle.links = [
        Link(
            id="inf_fire",
            target=mech_fire,
        ),
        Link(
            id="inf_rifle_cooldown",
            target=attr_cooldown,
        ),
    ]

    stock_scenario_section.links = [
        Link(
            id="inf_scenario_section_wolf_spawn",
            target=mech_wolf_spawn,
        ),
    ]

    stock_current_level.links = [
        Link(
            id="inf_current_level_wolf_spawn",
            target=mech_wolf_spawn,
        ),
    ]

    stock_time_passed.links = [
        Link(
            id="inf_time_passed_wolf_spawn",
            target=mech_wolf_spawn,
        ),
    ]

    # Attribute-like entities as sources
    attr_pos_cursor.links = [
        Link(
            id="inf_pos_call",
            target=mech_call,
        ),
        Link(
            id="inf_pos_sound",
            target=mech_sound,
        ),
        Link(
            id="inf_pos_fire",
            target=mech_fire,
        ),
    ]

    attr_player_position.links = [
        Link(
            id="inf_player_position_call",
            target=mech_call,
        ),
    ]

    # Mechanics as sources
    mech_movement.links = [
        Link(
            id="inf_movement_position",
            target=attr_player_position,
            granularity=1.0,
        ),
    ]

    mech_item_switch.links = [
        Link(
            id="inf_item_switch_available_items",
            target=attr_is_equipped,
            granularity=1.0,
        ),
    ]

    mech_call.links = [
        Link(
            id="inf_call_stick",
            target=attr_sheep_state,
            granularity=1.0,
        ),
    ]

    mech_sound.links = [
        Link(
            id="inf_sound_state",
            target=attr_sheep_state,
            granularity=2.0,
        ),
    ]

    mech_buy_items.links = [
        Link(
            id="inf_buy_items_available_items",
            target=stock_available_items,
            granularity=1.0,
        ),
        Link(
            id="inf_buy_items_coins",
            target=stock_coins,
            granularity=-3.0,
        ),
    ]

    mech_buy_sheep.links = [
        Link(
            id="inf_buy_sheep_sheep",
            target=stock_sheep,
            granularity=1.0,
        ),
        Link(
            id="inf_buy_sheep_coins",
            target=stock_coins,
            granularity=-1.0,
        ),
    ]

    mech_conversion.links = [
        Link(
            id="inf_coins_conversion",
            target=stock_coins,
            granularity=3.0,
        ),
    ]

    mech_graze.links = [
        Link(
            id="inf_graze_grazing_points",
            target=stock_grazing_points,
            granularity=2.0,
        ),
        Link(
            id="inf_graze_pasture_pp",
            target=attr_pasture_pp,
            granularity=1.0,
        ),
    ]

    mech_sheep_automation.links = [
        Link(
            id="inf_state_sheep_automation",
            target=attr_sheep_state,
        ),
    ]

    mech_fall.links = [
        Link(
            id="inf_sheep_fall",
            target=stock_sheep,
            granularity=-1.0,
        ),
    ]

    mech_fire.links = [
        Link(
            id="inf_cooldown_fire",
            target=attr_cooldown,
            granularity=1.0
        ),
        Link(
            id="inf_fire_projectiles",
            target=stock_projectiles,
            granularity=1.0,
        ),
    ]

    mech_impact.links = [
        Link(
            id="inf_sheep_impact",
            target=stock_sheep,
            granularity=-1.0,
        ),
        Link(
            id="inf_wolves_impact",
            target=stock_wolves,
            granularity=-1.0,
        ),
    ]

    mech_combat.links = [
        Link(
            id="inf_combat_sheep",
            target=stock_sheep,
            granularity=-1.0,
        ),
    ]

    mech_wolf_spawn.links = [
        Link(
            id="inf_wolf_spawn_wolves_global",
            target=stock_wolves,
            granularity=1.0,
        ),
    ]

    return Diagram(
        id="sheep_wolf_diagram",
        nodes=nodes,
    )


SHEEP_WOLF_DIAGRAM = create_sheep_wolf_diagram()

 
