# from CONDUIT_FORGE import src.
# from ..src import components
# from ..src import current
# from ..src import mosaic

from .decorators import timer
from conduitforge.components import (
    Component,
    MajorLossComponent,
    MinorLossComponent,
    Port,
    Pipe,
    T_connector,
    Elbow180DegFlanged,
    Elbow45DegThreaded,
    Elbow90DegChanferFlanged,
    Elbow90DegSmoothFlanged,
    Straight_Fitting,
)

from conduitforge.mosaic import Mosaic
from conduitforge.current import Current
from conduitforge.pump import Pump

import matplotlib

matplotlib.use("Qt5Agg")
# matplotlib.use("TkAgg")

import thermo
import sympy as sy
from uuid import UUID, uuid4
from ulid import ULID

import networkx as nx
import matplotlib.pyplot as plt


from mpl_toolkits.mplot3d import Axes3D
from typing import Optional
from pprint import pprint

from colorama import Fore, Back, Style


@timer
def comp_characteristic_eq():
    """
    This test was created to determinate if the components do have some variable
    inside all of its equations that is:
        1 - Unique
        2 - Is explicitly returned (as a Sy.Symbol) inside each and every componentequation

    If such variable exists, the second step is to verify of there are other característic
    variables inside each component.

    """
    pure_water = thermo.Chemical("water", T=303, P=300_000)  # temperature in Kelvin
    current_a = Current(composition=pure_water)

    #! THose in yellow (marked woth #//) are the old data, from when results where not converging
    # // p1 = Pipe(internal_diam=3, length=4, orientation=-90)
    # // p2 = Pipe(internal_diam=3, length=7, orientation=0)
    # // p3 = Pipe(internal_diam=3, length=4, orientation=90)
    # // p4 = Pipe(internal_diam=3, length=7, orientation=0)

    # //t1 = T_connector(internal_diam=3)
    # //t2 = T_connector(internal_diam=3)

    p1 = Pipe(internal_diam=0.05, length=4, orientation=-90)
    p2 = Pipe(internal_diam=0.05, length=7, orientation=0)
    p3 = Pipe(internal_diam=0.05, length=4, orientation=90)
    p4 = Pipe(internal_diam=0.05, length=7, orientation=0)

    t1 = T_connector(internal_diam=0.05)
    t2 = T_connector(internal_diam=0.05)

    # all_components: list[Component] = [p1, p2, p3, p4, t1, t2]

    print(f"\n{current_a.id = }")
    print(f"\n{current_a.pressure_name = }")

    print(f"\n{p1 = }")
    print(f"\n{p1.component_ports[0].id = }")
    print(f"\n{p1.component_ports[0].local_current.id = }")
    print(f"\n{p1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p1.component_ports[1].id = }")
    print(f"\n{p1.component_ports[1].local_current.id = }")
    print(f"\n{p1.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{p2 = }")
    print(f"\n{p2.component_ports[0].id = }")
    print(f"\n{p2.component_ports[0].local_current.id = }")
    print(f"\n{p2.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p2.component_ports[1].id = }")
    print(f"\n{p2.component_ports[1].local_current.id = }")
    print(f"\n{p2.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{p3 = }")
    print(f"\n{p3.component_ports[0].id = }")
    print(f"\n{p3.component_ports[0].local_current.id = }")
    print(f"\n{p3.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p3.component_ports[1].id = }")
    print(f"\n{p3.component_ports[1].local_current.id = }")
    print(f"\n{p3.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{p4 = }")
    print(f"\n{p4.component_ports[0].id = }")
    print(f"\n{p4.component_ports[0].local_current.id = }")
    print(f"\n{p4.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p4.component_ports[1].id = }")
    print(f"\n{p4.component_ports[1].local_current.id = }")
    print(f"\n{p4.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{t1 = }")
    print(f"\n{t1.component_ports[0].id = }")
    print(f"\n{t1.component_ports[0].local_current.id = }")
    print(f"\n{t1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{t1.component_ports[1].id = }")
    print(f"\n{t1.component_ports[1].local_current.id = }")
    print(f"\n{t1.component_ports[1].local_current.pressure_name = }\n")
    print(f"\n{t1.component_ports[2].id = }")
    print(f"\n{t1.component_ports[2].local_current.id = }")
    print(f"\n{t1.component_ports[2].local_current.pressure_name = }\n")
    print(f"\n{t1.component_ports[3].id = }")

    print(f"\n{t2 = }")
    print(f"\n{t2.component_ports[0].id = }")
    print(f"\n{t2.component_ports[0].local_current.id = }")
    print(f"\n{t2.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{t2.component_ports[1].id = }")
    print(f"\n{t2.component_ports[1].local_current.id = }")
    print(f"\n{t2.component_ports[1].local_current.pressure_name = }\n")
    print(f"\n{t2.component_ports[2].id = }")
    print(f"\n{t2.component_ports[2].local_current.id = }")
    print(f"\n{t2.component_ports[2].local_current.pressure_name = }\n")
    print(f"\n{t2.component_ports[3].id = }")

    m1: Optional[Mosaic] = t1 + current_a

    m1 = t1 + p1
    m1 = p1 + p2
    m1 = p2 + p3

    m1 = t1 + p4

    m1 = p4 + t2

    m1 = t2 + p3

    assert m1 is not None
    assert m1.graph is not None

    print(f"\n\n\n{m1.id = }\n\n\n")

    m1.automatic_solver(
        v_flow_guess=0.1,
        p_guess=200_000,
        generate_dir_graph=True,
        data_in_dir_graph=True,
        verify=True,
    )
    # m1.create_graph()
    # m1.create_graph_2()

    # # * print(f"\n{m1.graph.edges = }")

    # # m1.cycle_and_branch_identifier()
    # # m1.cycle_analyzer()

    # # print(f'\n\n{m1.simple_cycles_as_nodes = }')
    # # print(f'\n\n{m1.simple_cycles_as_edges = }')
    # # print(f'\n\n{m1.final_directed_cycles = }')

    # # * print(f"\n\n{len(m1.joints_list) = }\n{m1.joints_list = }\n\n")

    # # m1.first_mass_flow_guess()

    # components_as_uuids: dict[UUID, Component] = {
    #     comp.id: comp for comp in Component.component_objects
    # }

    if False:
        for joint in m1.joints_list:
            for id in joint:
                if id in components_as_uuids:
                    comp = components_as_uuids[id]
                    if len(comp.component_ports) != comp.port_quantity:
                        comp_root_port = comp.component_ports[-1]

                        assert comp_root_port is not None
                        for each_joint in m1.joints_list:
                            for each_id in each_joint:
                                if (comp_root_port.id in each_joint) or (
                                    comp_root_port.id in each_id
                                ):
                                    raise ValueError(f"""It seems that there is a root_port ({each_id=}) inside the joints of
                                                    the mosaic ({each_joint=}). Please, check if the component really have a 
                                                    root_port, and if the detected port is, indeed a root_port""")

    # m1.symple_q_p_guess()
    # m1.equation_gathering_from_graph()
    # m1.equations_solver()
    #! sanity check
    #! checking if the root_ports id and pressure names are not inside the
    #! all_variables list, from the m1 mosaic

    """
    # for comp in Component.component_objects:
    #     if (comp.location == m1.id) and (
    #         comp.port_quantity != len(comp.component_ports)
    #     ):
    #         comp_root_port = comp.component_ports[-1]
    #         comp_root_port_pressure_name = comp.component_ports[
    #             -1
    #         ].local_current.pressure_name

    #         assert comp_root_port.id not in m1.all_eq_variables
    #         assert comp_root_port_pressure_name not in m1.all_eq_variables

    #         assert sy.symbols(str(comp_root_port.id)) not in m1.all_eq_variables
    #         assert (
    #             sy.symbols(str(comp_root_port_pressure_name)) not in m1.all_eq_variables
    #         )

    #         assert str(comp_root_port.id) not in m1.all_eq_variables
    #         assert str(comp_root_port_pressure_name) not in m1.all_eq_variables

    #     elif (comp.location == m1.id) and (
    #         comp.port_quantity != len(comp.component_ports)
    #     ):
    #         for port in comp.component_ports:
    #             comp_port = port
    #             comp_pressure_name = comp_port.local_current.pressure_name
    #             assert comp_port.id in m1.all_eq_variables
    #             assert comp_pressure_name in m1.all_eq_variables

    #             assert sy.symbols(str(comp_port.id)) in m1.all_eq_variables
    #             assert sy.symbols(str(comp_port_pressure_name)) in m1.all_eq_variables

    #             assert str(comp_port.id) in m1.all_eq_variables
    #             assert str(comp_port_pressure_name) in m1.all_eq_variables
    """

    # normal_comp_uuid_map: dict[
    #     UUID, Component
    # ] = {}  # ! {comp.id:comp for comp in Component.component_objects}

    # not_normal_comp_uuid_map: dict[UUID, Component] = {}

    # for comp in Component.component_objects:
    #     if comp.location == m1.id:
    #         if comp.port_quantity != len(comp.component_ports):
    #             not_normal_comp_uuid_map[comp.id] = comp

    #             #! raise not NotImplementedError("ainda tenho q escrever os asserts")
    #         elif comp.port_quantity == len(comp.component_ports):
    #             normal_comp_uuid_map[comp.id] = comp
    #             #! raise not NotImplementedError("ainda tenho q escrever os asserts")

    # freedom_deg_number = len(m1.all_eq_variables) - len(m1.equation_list)

    # pprint(
    #     f"This is the number of variables in the system \
    #         {m1.all_eq_variables = }"
    # )

    # pprint(
    #     f"This is the number of variables in the system \
    #         {len(m1.all_eq_variables) = }"
    # )

    # pprint(
    #     f"This is the number of equations in the system \
    #         {len(m1.equation_list) = }"
    # )

    # pprint(
    #     f"This is the number of degrees of freedom of the equation system \
    #         {freedom_deg_number = }"
    # )

    # # // pprint(f"\n\n{m1.equation_list = }\n\n")

    # pprint(f"\n\n{m1.equations_dict = }\n\n")

    # print(f"{len(m1.equation_list) = }")

    # m1.equations_solver()

    # print(f"\n{m1.solved_system = }\n")

    # formated_solved_system: dict = dict(zip(m1.var_list, m1.solved_system))

    # pprint(f"{formated_solved_system = }")

    # # // This section is temporarely deactivated
    # if False:
    #     for comp in all_components:
    #         # print(f"\n{comp.id = }\n")

    #         if type(comp) is MajorLossComponent:
    #             major_comps.append(comp)

    #             for port in comp.component_ports:
    #                 comp_energy_eq = comp.energy_conservation(port_id=port.id)

    #                 if comp_energy_eq.free_symbols not in major_comps_var_dict:
    #                     major_comps_var_dict[comp_energy_eq.free_symbols] = comp

    #                 if comp_energy_eq.free_symbols not in all_comps_var_dict:
    #                     print(f"\n{comp_energy_eq.free_symbols = }\n")
    #                     print(
    #                         "\ncomp_energy_eq.free_symbols not in all_comps_var_dict:\n"
    #                     )
    #                     all_comps_var_dict[comp_energy_eq.free_symbols] = comp

    #         elif type(comp) is MinorLossComponent:
    #             minor_comps.append(comp)

    #             for port in comp.component_ports:
    #                 for another_port in comp.component_ports:
    #                     if (another_port is not port) and (
    #                         comp.energy_conservation(
    #                             ports_id=(port.id, another_port.id)
    #                         ).free_symbols
    #                         not in major_comps_var_dict
    #                     ):
    #                         comp_energy_eq = comp.energy_conservation(
    #                             ports_id=(port.id, another_port.id)
    #                         )

    #                         minor_comps_var_dict[comp_energy_eq.free_symbols] = comp

    #                     if comp_energy_eq.free_symbols not in all_comps_var_dict:
    #                         print(f"\n{comp_energy_eq.free_symbols = }\n")
    #                         print(
    #                             "\ncomp_energy_eq.free_symbols not in all_comps_var_dict:\n"
    #                         )
    #                         all_comps_var_dict[comp_energy_eq.free_symbols] = comp

    #         elif issubclass(type(comp), Component) is False:
    #             raise TypeError(f"{type(comp) = }")

    # # * pprint(all_comps_eq_list)

    # # print(f"\n\n{all_comps_var_dict = }")

    # # print(f"\n{len(m1.equations_dict.values()) = }\n{len(m1.equation_list) = }\n")

    # assert len(m1.equations_dict.values()) == len(m1.equation_list)

    # # // This part is temporarily deactivated
    # # if False:

    # # plt.ion()

    # plt.figure(1, figsize=(8, 6))

    # pos1 = nx.spring_layout(m1.graph, k=3, seed=16)

    # # Desenha o grafo com o layout escolhido, mostrando as conexões (arestas)
    # nx.draw(
    #     m1.graph,
    #     pos1,
    #     with_labels=True,
    #     node_color="lightblue",
    #     node_size=500,
    #     font_size=7,
    #     font_color="black",
    #     edge_color="gray",
    #     arrows=True,
    #     connectionstyle="arc3,rad=0.2",
    # )

    # # * Mostra o gráfico
    # plt.show(block=True)

    # # plt.figure(2, figsize=(8, 6))

    # # pos2 = nx.spring_layout(m1.acyclic_graph, seed=12)

    # # Desenha o grafo com o layout escolhido, mostrando as conexões (arestas)
    # # nx.draw(
    # #     m1.acyclic_graph,
    # #     pos2,
    # #     with_labels=True,
    # #     node_color="lightblue",
    # #     node_size=500,
    # #     font_size=7,
    # #     font_color="black",
    # #     edge_color="gray",
    # #     arrows=True,
    # #     connectionstyle="arc3,rad=0.2",
    # # )

    # # # * Mostra o gráfico
    # # plt.show(block=True)


@timer
def super_simplified_system():
    """
    This system will just be used to assure that the library is also capable of
    handling simple and/or small systems too.

    The system tested is shown below:

    ca -> p1
    """

    # Criação da composição química da corrente a
    pure_water = thermo.Chemical("water", T=303, P=30_000_000)  # temperature in Kelvin

    # Criação da corrente a
    ca = Current(composition=pure_water)

    # Criação do tubo 1
    p1 = Pipe(internal_diam=0.05, length=40, orientation=0)

    # Criação do mosaico 1
    m1 = p1 + ca

    print(f"\n{ca.id = }")
    print(f"\n{ca.pressure_name = }")

    print(f"\n{p1 = }")
    print(f"\n{p1.component_ports[0].id = }")
    print(f"\n{p1.component_ports[0].local_current.id = }")
    print(f"\n{p1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p1.component_ports[1].id = }")
    print(f"\n{p1.component_ports[1].local_current.id = }")
    print(f"\n{p1.component_ports[1].local_current.pressure_name = }\n")

    m1.create_graph_2()

    print(f"\n{m1.graph.edges = }")

    # m1.cycle_and_branch_identifier()
    # m1.cycle_analyzer()

    # print(f'\n\n{m1.simple_cycles_as_nodes = }')
    # print(f'\n\n{m1.simple_cycles_as_edges = }')
    # print(f'\n\n{m1.final_directed_cycles = }')

    print(f"\n\n{len(m1.joints_list) = }\n{m1.joints_list = }\n\n")

    # * m1.equation_gathering_from_graph()

    print(f"\n{ca.location = }")

    m1.symple_q_p_guess()
    m1.equation_gathering_from_graph()

    freedom_deg_number = len(m1.all_eq_variables) - len(m1.equation_list)

    pprint(
        f"This is the number of variables in the system \
            {m1.all_eq_variables = }"
    )

    pprint(
        f"This is the number of variables in the system \
            {len(m1.all_eq_variables) = }"
    )

    pprint(
        f"This is the number of equations in the system \
            {len(m1.equation_list) = }"
    )

    pprint(
        f"This is the number of degrees of freedom of the equation system \
            {freedom_deg_number = }"
    )

    # // pprint(f"\n\n{m1.equation_list = }\n\n")

    pprint(f"\n\n{m1.equations_dict = }\n\n")

    print(f"{len(m1.equation_list) = }")

    m1.equations_solver()

    print(f"\n{m1.solved_system = }\n")

    formated_solved_system: dict = dict(zip(m1.var_list, m1.solved_system))

    pprint(f"{formated_solved_system = }")

    # * m1.equations_solver()

    # print(f"\n{m1.solution_is_right = }\n")

    # m1.reynolds_convergence_step()
    print(f"\n{m1.solved_system = }\n")
    print(f"\n{m1.var_list = }\n")

    pprint(f"{len(m1.equation_list) = }\n")

    rounded_abs_visc: float = round(
        p1.component_ports[0].local_current.ab_viscosity(), 9
    )

    print(f"\nabs visc inside p1[0] local_cur: {rounded_abs_visc = }\n")

    print(f"\n{ca.ab_viscosity() = }\n")

    plt.figure(1, figsize=(8, 6))

    pos1 = nx.spring_layout(m1.graph, k=3, seed=16)

    # Desenha o grafo com o layout escolhido, mostrando as conexões (arestas)
    nx.draw(
        m1.graph,
        pos1,
        with_labels=False,
        node_color="lightblue",
        node_size=500,
        font_size=7,
        font_color="black",
        edge_color="gray",
        arrows=True,
        connectionstyle="arc3,rad=0.2",
    )

    print(f"\n{m1.graph.nodes(data = True)}\n")

    # * vol_flow = {d.get("vol_flow", "?")}

    # Criando rótulos personalizados (nome + atributo)
    labels = {
        n: f"{n}\npressure={d.get("pressure")}\nvol_flow={d.get("vol_flow")}"
        for n, d in m1.graph.nodes(data=True)
    }

    # # Criando rótulos personalizados (nome + atributo)
    # labels = {
    #     node: f"{node}\n({data["pressure (Pa)"]})"
    #     for node, data in m1.graph.nodes(data=True)
    # }

    # Desenhando os rótulos customizados
    nx.draw_networkx_labels(m1.graph, pos1, labels, font_size=9, font_color="black")

    # * Mostra o gráfico
    plt.show(block=True)


@timer
def super_simplified_system_with_pump():
    """
    This system will just be used to assure that the library is also capable of
    handling simple and/or small systems too.

    The system tested is shown below:

    ca -> pump1 -> p1
    """
    pure_water = thermo.Chemical("water", T=303, P=300_000)  # temperature in Kelvin
    ca = Current(composition=pure_water)

    # // internal_diam = 0.05 (m?) if forgot if this diam is measured in meters
    # // or in mm

    # // mechanical_power = 200 Watt (1 Watt = 1 J/s)
    # // efficiency = 0.85 = 85%
    pump1 = Pump(0.05, 5000, 0.85)

    p1 = Pipe(internal_diam=0.05, length=4, orientation=0)

    m1 = p1 + ca
    m1 = p1 + pump1

    print(f"\n{ca.id = }")
    print(f"\n{ca.pressure_name = }")

    print(f"\n{p1 = }")
    print(f"\n{p1.component_ports[0].id = }")
    print(f"\n{p1.component_ports[0].local_current.id = }")
    print(f"\n{p1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p1.component_ports[1].id = }")
    print(f"\n{p1.component_ports[1].local_current.id = }")
    print(f"\n{p1.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{pump1 = }")
    print(f"\n{pump1.component_ports[0].id = }")
    print(f"\n{pump1.component_ports[0].local_current.id = }")
    print(f"\n{pump1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{pump1.component_ports[1].id = }")
    print(f"\n{pump1.component_ports[1].local_current.id = }")
    print(f"\n{pump1.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{m1.id = }\n")

    m1.create_graph_2()

    print(f"\n{m1.graph.edges = }")

    # m1.cycle_and_branch_identifier()
    # m1.cycle_analyzer()

    # print(f'\n\n{m1.simple_cycles_as_nodes = }')
    # print(f'\n\n{m1.simple_cycles_as_edges = }')
    # print(f'\n\n{m1.final_directed_cycles = }')

    print(f"\n\n{len(m1.joints_list) = }\n{m1.joints_list = }\n\n")

    m1.symple_q_p_guess()
    m1.equation_gathering_from_graph()

    pprint(f"\n{m1.equations_dict = }\n")
    print(f"{len(m1.equations_dict) = }")
    print(f"{len(m1.equations_dict.values()) = }")
    print(f"{len(m1.equations_dict.keys()) = }")

    pprint(f"\n\n{m1.equation_list = }\n\n")

    pprint(f"{len(m1.equation_list) = }")

    print(f"\n{ca.location = }")

    m1.equations_solver()

    print(f"\n{m1.solved_system = }\n")

    formated_solved_system: dict = dict(zip(m1.var_list, m1.solved_system))

    pprint(f"{formated_solved_system = }")

    plt.figure(1, figsize=(8, 6))

    pos1 = nx.spring_layout(m1.graph, k=3, seed=16)

    # Desenha o grafo com o layout escolhido, mostrando as conexões (arestas)
    nx.draw(
        m1.graph,
        pos1,
        with_labels=True,
        node_color="lightblue",
        node_size=500,
        font_size=7,
        font_color="black",
        edge_color="gray",
        arrows=True,
        connectionstyle="arc3,rad=0.2",
    )

    # * Mostra o gráfico
    plt.show(block=True)


@timer
def simple_mosaic_pump_test_pressurization():
    """
    This test will be used to verify if the pump and the pump equations are
    working correctly for a single branch mosaic, with a pump on one of its
    ends (in the beggining, or in the end)

    I'll also calculate all the pressures and volume flows for this system manually,
    to assure that the equations built by the mosaic are right

    The original current will be plugged into the "entry of the pump", as shown
    below

                        p3
                         ^
                         |
    ca -> pump1 -> p1 -> p2
    """
    pure_water = thermo.Chemical("water", T=303, P=300_000)  # temperature in Kelvin
    ca = Current(composition=pure_water)

    p1 = Pipe(internal_diam=3, length=4, orientation=0)
    p2 = Pipe(internal_diam=3, length=7, orientation=0)
    p3 = Pipe(internal_diam=3, length=4, orientation=90)

    # // internal_diam = 3 m
    # // mechanical_power = 200 Watt
    # // efficiency = 0.85 = 85%
    pump1 = Pump(3, 200, 0.85)

    m1 = pump1 + ca
    m1 = pump1 + p1
    m1 = p1 + p2
    m1 = p2 + p3

    print(f"\n{ca.id = }")
    print(f"\n{ca.pressure_name = }")

    print(f"\n{p1 = }")
    print(f"\n{p1.component_ports[0].id = }")
    print(f"\n{p1.component_ports[0].local_current.id = }")
    print(f"\n{p1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p1.component_ports[1].id = }")
    print(f"\n{p1.component_ports[1].local_current.id = }")
    print(f"\n{p1.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{p2 = }")
    print(f"\n{p2.component_ports[0].id = }")
    print(f"\n{p2.component_ports[0].local_current.id = }")
    print(f"\n{p2.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p2.component_ports[1].id = }")
    print(f"\n{p2.component_ports[1].local_current.id = }")
    print(f"\n{p2.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{p3 = }")
    print(f"\n{p3.component_ports[0].id = }")
    print(f"\n{p3.component_ports[0].local_current.id = }")
    print(f"\n{p3.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p3.component_ports[1].id = }")
    print(f"\n{p3.component_ports[1].local_current.id = }")
    print(f"\n{p3.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{pump1 = }")
    print(f"\n{pump1.component_ports[0].id = }")
    print(f"\n{pump1.component_ports[0].local_current.id = }")
    print(f"\n{pump1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{pump1.component_ports[1].id = }")
    print(f"\n{pump1.component_ports[1].local_current.id = }")
    print(f"\n{pump1.component_ports[1].local_current.pressure_name = }\n")

    m1.create_graph_2()

    print(f"\n{m1.graph.edges = }")

    print(f"\n\n{len(m1.joints_list) = }\n{m1.joints_list = }\n\n")

    m1.equation_gathering_from_graph()

    pprint(f"\n{m1.equations_dict = }\n")
    print(f"{len(m1.equations_dict) = }")
    print(f"{len(m1.equations_dict.values()) = }")
    print(f"{len(m1.equations_dict.keys()) = }")

    pprint(f"\n\n{m1.equation_list = }\n\n")

    pprint(f"{len(m1.equation_list) = }")

    print(f"\n{ca.location = }")

    m1.equations_solver()

    print(f"\n{m1.solved_system = }\n")

    print(f"\n{m1.var_list = }\n")

    plt.figure(1, figsize=(8, 6))

    pos1 = nx.spring_layout(m1.graph, k=3, seed=16)

    # Desenha o grafo com o layout escolhido, mostrando as conexões (arestas)
    nx.draw(
        m1.graph,
        pos1,
        with_labels=True,
        node_color="lightblue",
        node_size=500,
        font_size=7,
        font_color="black",
        edge_color="gray",
        arrows=True,
        connectionstyle="arc3,rad=0.2",
    )

    # * Mostra o gráfico
    plt.show(block=True)


@timer
def simple_mosaic_pump_test_pressurizing():
    """
    This test will be used to verify if the pump and the pump equations are
    working correctly for a single branch mosaic, with a pump on one of its
    ends (in the beggining, or in the end)

    I'll also calculate all the pressures and volume flows for this system manually,
    to assure that the equations built by the mosaic are right

    The original current will be plugged into the "entry of the pump", as shown
    below

                        p3
                         ^
                         |
    ca -> pump1 -> p1 -> p2
    """
    pure_water = thermo.Chemical("water", T=303, P=300_000)  # temperature in Kelvin
    ca = Current(composition=pure_water)

    p1 = Pipe(internal_diam=3, length=4, orientation=0)
    p2 = Pipe(internal_diam=3, length=7, orientation=0)
    p3 = Pipe(internal_diam=3, length=4, orientation=90)

    pump1 = Pump(200, 0.85)

    m1 = ca + pump1
    m1 = pump1 + p1
    m1 = p1 + p2
    m1 = p2 + p3


@timer
def simple_mosaic_pump_test_vacum_suction():
    """
    This test will be used to verify if the pump and the pump equations are
    working correctly for a single branch mosaic, with a pump on one of its
    ends (in the beggining, or in the end)

    I'll also calculate all the pressures and volume flows for this system manually,
    to assure that the equations built by the mosaic are right

    The original current will be plugged into the "entry of the pump", as shown
    below

                        pump1
                         ^
                         |
    ca -> p1 -> p2 ->  p3
    """
    pure_water = thermo.Chemical("water", T=303, P=300_000)  # temperature in Kelvin
    ca = Current(composition=pure_water)

    #!internal_diam = 3 cm, length = 40 cm and 70 cm

    p1 = Pipe(internal_diam=0.03, length=0.4, orientation=0)
    p2 = Pipe(internal_diam=0.03, length=0.7, orientation=0)
    p3 = Pipe(internal_diam=0.03, length=0.4, orientation=90)

    #! 200 Watts of Power, and 0.85 of efficiency (85% of efficiency)
    pump1 = Pump(200, 0.85)

    m1 = ca + p1
    m1 = p1 + p2
    m1 = p2 + p3
    m1 = p3 + pump1


@timer
def simple_mosaic_test():
    """
    This test will be used to verify if simple mosaics are solved correctly

    The mosaic solved is shown below
                 p2

                 ^
                 |
    ca -> p1 -> t1 -> p3

    """

    pure_water = thermo.Chemical("water", T=293.15, P=300_000)  # temperature in Kelvin
    ca = Current(composition=pure_water)

    p1 = Pipe(internal_diam=0.03, length=0.4, orientation=0)
    p2 = Pipe(internal_diam=0.03, length=0.7, orientation=90)
    p3 = Pipe(internal_diam=0.03, length=0.4, orientation=0)

    t1 = T_connector(internal_diam=3)

    print(f"\n{ca.id = }")
    print(f"\n{ca.pressure_name = }")

    print(f"\n{p1 = }")
    print(f"\n{p1.component_ports[0].id = }")
    print(f"\n{p1.component_ports[0].local_current.id = }")
    print(f"\n{p1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p1.component_ports[1].id = }")
    print(f"\n{p1.component_ports[1].local_current.id = }")
    print(f"\n{p1.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{p2 = }")
    print(f"\n{p2.component_ports[0].id = }")
    print(f"\n{p2.component_ports[0].local_current.id = }")
    print(f"\n{p2.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p2.component_ports[1].id = }")
    print(f"\n{p2.component_ports[1].local_current.id = }")
    print(f"\n{p2.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{p3 = }")
    print(f"\n{p3.component_ports[0].id = }")
    print(f"\n{p3.component_ports[0].local_current.id = }")
    print(f"\n{p3.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{p3.component_ports[1].id = }")
    print(f"\n{p3.component_ports[1].local_current.id = }")
    print(f"\n{p3.component_ports[1].local_current.pressure_name = }\n")

    print(f"\n{t1 = }")
    print(f"\n{t1.component_ports[0].id = }")
    print(f"\n{t1.component_ports[0].local_current.id = }")
    print(f"\n{t1.component_ports[0].local_current.pressure_name = }\n")
    print(f"\n{t1.component_ports[1].id = }")
    print(f"\n{t1.component_ports[1].local_current.id = }")
    print(f"\n{t1.component_ports[1].local_current.pressure_name = }\n")
    print(f"\n{t1.component_ports[2].id = }")
    print(f"\n{t1.component_ports[2].local_current.id = }")
    print(f"\n{t1.component_ports[2].local_current.pressure_name = }\n")
    print(f"\n{t1.component_ports[3].id = }")

    m1 = p1 + ca
    m1 = p1 + t1
    m1 = t1 + p2
    m1 = t1 + p3

    m1.create_graph_2()

    m1.symple_q_p_guess()
    m1.equation_gathering_from_graph()

    freedom_deg_number = len(m1.all_eq_variables) - len(m1.equation_list)

    pprint(
        f"This is the number of variables in the system \
            {m1.all_eq_variables = }"
    )

    pprint(
        f"This is the number of variables in the system \
            {len(m1.all_eq_variables) = }"
    )

    pprint(
        f"This is the number of equations in the system \
            {len(m1.equation_list) = }"
    )

    pprint(
        f"This is the number of degrees of freedom of the equation system \
            {freedom_deg_number = }"
    )

    pprint(f"\n\n{m1.equations_dict = }\n\n")

    print(f"{len(m1.equation_list) = }")

    m1.equations_solver()

    print(f"\n{m1.solved_system = }\n")

    formated_solved_system: dict = dict(zip(m1.var_list, m1.solved_system))

    pprint(f"{formated_solved_system = }")

    print(f"\n\n{m1.graph.nodes() = }\n")
    print(f"\n{list(m1.graph.nodes()) = }\n")
    print(f"\n{list(m1.graph.nodes())[0] = }\n")
    print(f"\n{type(list(m1.graph.nodes())[0]) = }\n")
    print(f"\n{str(list(m1.graph.nodes())[0]) = }\n")

    print(f"\n\n{m1.var_list = }\n")
    print(f"\n{m1.var_list[0] = }\n")
    print(f"\n{type(m1.var_list[0]) = }\n")
    print(f"\n{str(m1.var_list[0]) = }\n")

    plt.figure(1, figsize=(8, 6))

    pos1 = nx.spring_layout(m1.graph, k=3, seed=12)

    # Desenha o grafo com o layout escolhido, mostrando as conexões (arestas)
    nx.draw(
        m1.graph,
        pos1,
        with_labels=True,
        node_color="lightblue",
        node_size=500,
        font_size=7,
        font_color="black",
        edge_color="gray",
        arrows=True,
        connectionstyle="arc3,rad=0.2",
    )

    # * Mostra o gráfico
    plt.show(block=True)

    plt.figure(2, figsize=(8, 6))

    pos2 = nx.spring_layout(nx.to_undirected(m1.graph), seed=12)

    # * Desenhar o grafico com o layout escolhido, mostrando as conexões (arestas)
    nx.draw(
        nx.to_undirected(m1.graph),
        pos2,
        with_labels=True,
        node_color="lightblue",
        node_size=500,
        font_size=12,
        font_color="black",
        edge_color="gray",
        arrows=True,
        connectionstyle="arc3,rad=0.2",
    )

    # * Mostra o gráfico
    plt.show(block=True)


@timer
def simple_mosaic_with_pressurising_pump():
    """
    This test will be used to verify if simple mosaics are solved correctly

    The mosaic solved is shown below
                         p2

                         ^
                         |
    ca -> pump1 -> p1 ->t1 -> p3

    """


@timer
def experimental_solving_algorithm():
    """
    This test will be used to see if the system converges to a resonable answer

    The algorithm is to use the quesses valoues to calculate Re and f in each point of the
    mosaic. The constant values will be fed to the energy_conservation method, to calculate
    the head pressure loss. After the sy.nsolve() method runs, the values for Q will be
    used to calculate Re and f again, untill both the variables system (Qi, Pi) and the
    Re and f values for all system converge.

    The problem is that i do not know if it will not converge, or if the convergent will be
    slower than the normal method, or if there will be some Q, P, Re and or f that will
    never converge, but all those values converge for all of the other points in the system
    """
    pure_water = thermo.Chemical("water", T=303)  # temperature in Kelvin
    current_a = Current(composition=pure_water, P=300_000)

    p1 = Pipe(internal_diam=3, length=4, orientation=-90)
    p2 = Pipe(internal_diam=3, length=7, orientation=0)


@timer
def fitting_test():
    """
    This test is created to evaluate the behaviour of fittings, just to assure
    that every thing with this objects is running right.
    """

    """
    Creation of the sollowing system:
    
    ca -> p1 -> elbow
                  |
                    > p2 ->
    """

    water = thermo.Chemical("water", T=293.15, P=300_000)  # temperature in Kelvin
    ca = Current(composition=water)

    p1 = Pipe(internal_diam=0.03, length=0.4, orientation=0)
    p2 = Pipe(internal_diam=0.03, length=0.7, orientation=0)

    elb1 = Elbow90DegSmoothFlanged(internal_diam=0.03)

    m1 = p1 + ca
    m1 = p1 + elb1
    m1 = elb1 + p2

    m1.automatic_solver(
        v_flow_guess=5,
        p_guess=200_000,
        generate_dir_graph=True,
        data_in_dir_graph=True,
        verify=True,
    )


if __name__ == "__main__":
    # ? comp_characteristic_eq()

    # *simple_mosaic_test()

    # ? super_simplified_system()

    # // The next test to be evaluated is the
    # // super_simplified_system_with_pump()

    # // super_simplified_system_with_pump()

    # * simple_mosaic_pump_test_pressurization()

    # * experimental_solving_algorithm()

    # * super_simplified_system_with_pump()

    fitting_test()
