from .database import ChangeSet
from .s0_base import is_junction, get_nodes
from .s9_demands import get_demand
from .s32_region_util import Topology, get_nodes_in_region
from .batch_exe import execute_batch_command


DISTRIBUTION_TYPE_ADD = 'ADD'
DISTRIBUTION_TYPE_OVERRIDE = 'OVERRIDE'


def calculate_demand_to_nodes(name: str, demand: float, nodes: list[str]) -> dict[str, float]:
    if len(nodes) == 0 or demand == 0.0:
        return {}

    topology = Topology(name, nodes)
    t_nodes = topology.nodes()
    t_links = topology.links()

    length_sum = 0.0
    for value in t_links.values():
        length_sum += abs(value['length'])

    if length_sum <= 0.0:
        return {}

    demand_per_length = demand / length_sum

    result: dict[str, float] = {}
    for node, value in t_nodes.items():
        if not is_junction(name, node):
            continue
        demand_per_node = 0.0
        for link in value['links']:
            demand_per_node += abs(t_links[link]['length']) * demand_per_length * 0.5
        result[node] = demand_per_node

    return result


def calculate_demand_to_region(name: str, demand: float, region: str) -> dict[str, float]:
    nodes = get_nodes_in_region(name, region)
    return calculate_demand_to_nodes(name, demand, nodes)


def calculate_demand_to_network(name: str, demand: float) -> dict[str, float]:
    nodes = get_nodes(name)
    return calculate_demand_to_nodes(name, demand, nodes)


def distribute_demand_to_nodes(name: str, demand: float, nodes: list[str], type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet:
    if len(nodes) == 0 or demand == 0.0:
        return ChangeSet()
    if type != DISTRIBUTION_TYPE_ADD and type != DISTRIBUTION_TYPE_OVERRIDE:
        return ChangeSet()

    topology = Topology(name, nodes)
    t_nodes = topology.nodes()
    t_links = topology.links()

    length_sum = 0.0
    for value in t_links.values():
        length_sum += abs(value['length'])
    
    if length_sum <= 0.0:
        return ChangeSet()
    
    demand_per_length = demand / length_sum

    cs = ChangeSet()

    for node, value in t_nodes.items():
        if not is_junction(name, node):
            continue
        demand_per_node = 0.0
        for link in value['links']:
            demand_per_node += abs(t_links[link]['length']) * demand_per_length * 0.5

        ds = get_demand(name, node)['demands']
        if len(ds) == 0:
            ds = [{'demand': demand_per_node, 'pattern': None, 'category': None}]
        elif type == DISTRIBUTION_TYPE_ADD:
            ds[0]['demand'] += demand_per_node
        else:
            ds[0]['demand'] = demand_per_node
        cs.update({'type': 'demand', 'junction': node, 'demands': ds})

    return execute_batch_command(name, cs)


def distribute_demand_to_region(name: str, demand: float, region: str, type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet:
    nodes = get_nodes_in_region(name, region)
    return distribute_demand_to_nodes(name, demand, nodes, type)

def get_total_base_demand(name:str,region:str)->float:
    nodes = get_nodes_in_region(name, region)
    t_demands=0.0
    for node  in nodes:
        if not is_junction(name, node):
           continue
        ds = get_demand(name, node)['demands']
        t_demands= t_demands+ds[0]['demand']
         
    return t_demands