from .database import ChangeSet, g_delete_prefix, API_DELETE, API_UPDATE, try_read
from .sections import *

from .s0_base import *

from .s3_reservoirs import unset_reservoir_by_pattern
from .s4_tanks import unset_tank_by_curve
from .s6_pumps import unset_pump_by_curve, unset_pump_by_pattern
from .s8_tags import delete_tag_by_node, delete_tag_by_link
from .s9_demands import delete_demand_by_junction, unset_demand_by_pattern
from .s10_status import delete_status_by_link
from .s15_energy import delete_pump_energy_by_pump, unset_pump_energy_by_pattern, unset_pump_energy_by_curve
from .s16_emitters import delete_emitter_by_junction
from .s17_quality import delete_quality_by_node
from .s18_sources import delete_source_by_node, unset_source_by_pattern
from .s19_reactions import delete_pipe_reaction_by_pipe, delete_tank_reaction_by_tank
from .s20_mixing import delete_mixing_by_tank
from .s25_vertices import delete_vertex_by_link
from .s26_labels import unset_label_by_node

from .s23_options_util import generate_v2, generate_v3


def delete_junction_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from junctions where id = '{id}'")
    if row == None:
        return result

    links = get_node_links(name, id)

    for link in links:
        if is_pipe(name, link):
            result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
        if is_pump(name, link):
            result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
        if is_valve(name, link):
            result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))

    result.merge(delete_tag_by_node(name, id))
    result.merge(delete_demand_by_junction(name, id))
    result.merge(delete_emitter_by_junction(name, id))
    result.merge(delete_quality_by_node(name, id))
    result.merge(delete_source_by_node(name, id))
    result.merge(unset_label_by_node(name, id))
    result.merge(cs)

    return result


def delete_reservoir_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from reservoirs where id = '{id}'")
    if row == None:
        return result

    links = get_node_links(name, id)

    for link in links:
        if is_pipe(name, link):
            result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
        if is_pump(name, link):
            result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
        if is_valve(name, link):
            result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))

    result.merge(delete_tag_by_node(name, id))
    result.merge(delete_quality_by_node(name, id))
    result.merge(delete_source_by_node(name, id))
    result.merge(unset_label_by_node(name, id))
    result.merge(cs)

    return result


def delete_tank_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from tanks where id = '{id}'")
    if row == None:
        return result

    links = get_node_links(name, id)

    for link in links:
        if is_pipe(name, link):
            result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
        if is_pump(name, link):
            result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
        if is_valve(name, link):
            result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))

    result.merge(delete_tag_by_node(name, id))
    result.merge(delete_quality_by_node(name, id))
    result.merge(delete_source_by_node(name, id))
    result.merge(delete_tank_reaction_by_tank(name, id))
    result.merge(delete_mixing_by_tank(name, id))
    result.merge(unset_label_by_node(name, id))
    result.merge(cs)

    return result


def delete_pipe_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from pipes where id = '{id}'")
    if row == None:
        return result

    result.merge(delete_tag_by_link(name, id))
    result.merge(delete_status_by_link(name, id))
    result.merge(delete_pipe_reaction_by_pipe(name, id))
    result.merge(delete_vertex_by_link(name, id))
    result.merge(cs)

    return result


def delete_pump_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from pumps where id = '{id}'")
    if row == None:
        return result

    result.merge(delete_tag_by_link(name, id))
    result.merge(delete_status_by_link(name, id))
    result.merge(delete_pump_energy_by_pump(name, id))
    result.merge(delete_vertex_by_link(name, id))
    result.merge(cs)

    return result


def delete_valve_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from valves where id = '{id}'")
    if row == None:
        return result

    result.merge(delete_tag_by_link(name, id))
    result.merge(delete_status_by_link(name, id))
    result.merge(delete_vertex_by_link(name, id))

    result.merge(cs)

    return result


def delete_pattern_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from _pattern where id = '{id}'")
    if row == None:
        return result

    result.merge(unset_reservoir_by_pattern(name, id))
    result.merge(unset_pump_by_pattern(name, id))
    result.merge(unset_demand_by_pattern(name, id))
    result.merge(unset_pump_energy_by_pattern(name, id))
    result.merge(unset_source_by_pattern(name, id))
    result.merge(cs)

    return result


def delete_curve_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
    result = ChangeSet()

    id = cs.operations[0]['id']
    row = try_read(name, f"select * from _curve where id = '{id}'")
    if row == None:
        return result

    result.merge(unset_tank_by_curve(name, id))
    result.merge(unset_pump_by_curve(name, id))
    result.merge(unset_pump_energy_by_curve(name, id))
    result.merge(cs)

    return result


def set_option_cs(cs: ChangeSet) -> ChangeSet:
    cs.operations[0]['operation'] = API_UPDATE
    cs.operations[0]['type'] = 'option'
    new_cs = cs
    new_cs.merge(generate_v3(cs))
    return new_cs


def set_option_v3_cs(cs: ChangeSet) -> ChangeSet:
    cs.operations[0]['operation'] = API_UPDATE
    cs.operations[0]['type'] = 'option_v3'
    new_cs = cs
    new_cs.merge(generate_v2(cs))
    return new_cs


def rewrite_batch_api(name: str, cs: ChangeSet) -> ChangeSet:
    op = cs.operations[0]
    api = op['operation']
    type = op['type']

    if api == API_DELETE:
        if type == s2_junction:
            return delete_junction_cascade_batch_cs(name, cs)
        elif type == s3_reservoir:
            return delete_reservoir_cascade_batch_cs(name, cs)
        elif type == s4_tank:
            return delete_tank_cascade_batch_cs(name, cs)
        elif type == s5_pipe:
            return delete_pipe_cascade_batch_cs(name, cs)
        elif type == s6_pump:
            return delete_pump_cascade_batch_cs(name, cs)
        elif type == s7_valve:
            return delete_valve_cascade_batch_cs(name, cs)
        elif type == s11_pattern:
            return delete_pattern_cascade_batch_cs(name, cs)
        elif type == s12_curve:
            return delete_curve_cascade_batch_cs(name, cs)
    elif api == API_UPDATE:
        if type == s23_option:
            return set_option_cs(cs)
        elif type == s23_option_v3:
            return set_option_v3_cs(cs)

    return cs
