import json
from datetime import datetime
from math import pi, sqrt

import pytz

import app.services.simulation as simulation
from app.algorithms.simulation.runner import (
    run_simulation_ex,
    from_clock_to_seconds_2,
)
from app.infra.epanet.epanet import Output
from app.services.scheme_management import store_scheme_info
from app.services.tjnetwork import (
    ChangeSet,
    OPTION_DEMAND_MODEL_PDA,
    OPTION_QUALITY_CHEMICAL,
    SOURCE_TYPE_SETPOINT,
    add_pattern,
    add_source,
    close_project,
    copy_project,
    delete_project,
    get_demand,
    get_emitter,
    get_node_links,
    get_option,
    get_pattern,
    get_pipe,
    get_source,
    get_time,
    have_project,
    is_junction,
    is_project_open,
    open_project,
    set_demand,
    set_emitter,
    set_option,
    set_source,
    set_time,
)


############################################################
# burst analysis 01
############################################################
def convert_to_local_unit(proj: str, emitters: float) -> float:
    open_project(proj)
    proj_opt = get_option(proj)
    str_unit = proj_opt.get("UNITS")

    if str_unit == "CMH":
        return emitters * 3.6
    elif str_unit == "LPS":
        return emitters
    elif str_unit == "CMS":
        return emitters / 1000.0
    elif str_unit == "MGD":
        return emitters * 0.0438126

    # Unknown unit: log and return original value
    print(str_unit)
    return emitters


def burst_analysis(
    name: str,
    modify_pattern_start_time: str,
    burst_ID: list | str = None,
    burst_size: list | float | int = None,
    modify_total_duration: int = 900,
    modify_fixed_pump_pattern: dict[str, list] = None,
    modify_variable_pump_pattern: dict[str, list] = None,
    modify_valve_opening: dict[str, float] = None,
    scheme_name: str = None,
) -> None:
    """
    爆管模拟
    :param name: 模型名称，数据库中对应的名字
    :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
    :param burst_ID: 爆管管道的ID，选取的是管道，单独传入一个爆管管道，可以是str或list，传入多个爆管管道是用list
    :param burst_size: 爆管管道破裂的孔口面积，和burst_ID列表各位置的ID对应，以cm*cm计算
    :param modify_total_duration: 模拟总历时，秒
    :param modify_fixed_pump_pattern: dict中包含多个水泵模式，str为工频水泵的id，list为修改后的pattern
    :param modify_variable_pump_pattern: dict中包含多个水泵模式，str为变频水泵的id，list为修改后的pattern
    :param modify_valve_opening: dict中包含多个阀门开启度，str为阀门的id，float为修改后的阀门开启度
    :param scheme_name: 方案名称
    :return:
    """
    scheme_detail: dict = {
        "burst_ID": burst_ID,
        "burst_size": burst_size,
        "modify_total_duration": modify_total_duration,
        "modify_fixed_pump_pattern": modify_fixed_pump_pattern,
        "modify_variable_pump_pattern": modify_variable_pump_pattern,
        "modify_valve_opening": modify_valve_opening,
    }
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"burst_Anal_{name}"
    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(name + "_template", new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Opening Database."
    )
    open_project(new_name)
    simulation.run_simulation(
        name=new_name,
        simulation_type="manually_temporary",
        modify_pattern_start_time=modify_pattern_start_time,
    )
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Database Loading OK."
    )
    ##step 1 set the emitter coefficient of end node of busrt pipe
    if isinstance(burst_ID, list):
        if (burst_size is not None) and (type(burst_size) is not list):
            return json.dumps("Type mismatch.")
    # 转化为列表形式
    elif isinstance(burst_ID, str):
        burst_ID = [burst_ID]
        if burst_size is not None:
            if isinstance(burst_size, float) or isinstance(burst_size, int):
                burst_size = [burst_size]
            else:
                return json.dumps("Type mismatch.")
    else:
        return json.dumps("Type mismatch.")
    if burst_size is None:
        burst_size = [-1] * len(burst_ID)
    elif len(burst_size) < len(burst_ID):
        burst_size += [-1] * (len(burst_ID) - len(burst_size))
    elif len(burst_size) > len(burst_ID):
        # burst_size = burst_size[:len(burst_ID)]
        return json.dumps("Length mismatch.")
    for burst_ID_, burst_size_ in zip(burst_ID, burst_size):
        pipe = get_pipe(new_name, burst_ID_)
        str_start_node = pipe["node1"]
        str_end_node = pipe["node2"]
        d_pipe = pipe["diameter"] / 1000.0
        if burst_size_ <= 0:
            burst_size_ = 3.14 * d_pipe * d_pipe / 4 / 8
        else:
            burst_size_ = burst_size_ / 10000
        emitter_coeff = (
            0.65 * burst_size_ * sqrt(19.6) * 1000
        )  # 1/8开口面积作为coeff，单位 L/S
        emitter_coeff = convert_to_local_unit(new_name, emitter_coeff)
        emitter_node = ""
        if is_junction(new_name, str_end_node):
            emitter_node = str_end_node
        elif is_junction(new_name, str_start_node):
            emitter_node = str_start_node
        old_emitter = get_emitter(new_name, emitter_node)
        if old_emitter != None:
            old_emitter["coefficient"] = emitter_coeff  # 爆管的emitter coefficient设置
        else:
            old_emitter = {"junction": emitter_node, "coefficient": emitter_coeff}
        new_emitter = ChangeSet()
        new_emitter.append(old_emitter)
        set_emitter(new_name, new_emitter)
    # step 2. run simulation
    # 涉及关阀计算，可能导致关阀后仍有流量，改为压力驱动PDA
    options = get_option(new_name)
    options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA
    options["REQUIRED PRESSURE"] = "10.0000"
    cs_options = ChangeSet()
    cs_options.append(options)
    set_option(new_name, cs_options)
    # valve_control = None
    # if modify_valve_opening is not None:
    #     valve_control = {}
    #     for valve in modify_valve_opening:
    #         valve_control[valve] = {'status': 'CLOSED'}
    # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time,
    #                            end_datetime=modify_pattern_start_time,
    #                            modify_total_duration=modify_total_duration,
    #                            modify_pump_pattern=modify_pump_pattern,
    #                            valve_control=valve_control,
    #                            downloading_prohibition=True)
    simulation.run_simulation(
        name=new_name,
        simulation_type="extended",
        modify_pattern_start_time=modify_pattern_start_time,
        modify_total_duration=modify_total_duration,
        modify_fixed_pump_pattern=modify_fixed_pump_pattern,
        modify_variable_pump_pattern=modify_variable_pump_pattern,
        modify_valve_opening=modify_valve_opening,
        scheme_type="burst_analysis",
        scheme_name=scheme_name,
    )
    # step 3. restore the base model status
    # execute_undo(name) #有疑惑
    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)
    # 存储方案信息到 PG 数据库
    store_scheme_info(
        name=name,
        scheme_name=scheme_name,
        scheme_type="burst_analysis",
        username="admin",
        scheme_start_time=modify_pattern_start_time,
        scheme_detail=scheme_detail,
    )


############################################################
# valve closing analysis 02
############################################################
def valve_close_analysis(
    name: str,
    modify_pattern_start_time: str,
    modify_total_duration: int = 900,
    modify_valve_opening: dict[str, float] = None,
    scheme_name: str = None,
) -> None:
    """
    关阀模拟
    :param name: 模型名称，数据库中对应的名字
    :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
    :param modify_total_duration: 模拟总历时，秒
    :param modify_valve_opening:  dict中包含多个阀门开启度，str为阀门的id，float为修改后的阀门开启度
    :param scheme_name: 方案名称
    :return:
    """
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"valve_close_Anal_{name}"
    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(name + "_template", new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Opening Database."
    )
    open_project(new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Database Loading OK."
    )
    # step 1. change the valves status to 'closed'
    # for valve in valves:
    #     if not is_valve(new_name,valve):
    #         result='ID:{}is not a valve type'.format(valve)
    #         return result
    #     cs=ChangeSet()
    #     status=get_status(new_name,valve)
    #     status['status']='CLOSED'
    #     cs.append(status)
    #     set_status(new_name,cs)
    # step 2. run simulation
    # 涉及关阀计算，可能导致关阀后仍有流量，改为压力驱动PDA
    options = get_option(new_name)
    options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA
    options["REQUIRED PRESSURE"] = "20.0000"
    cs_options = ChangeSet()
    cs_options.append(options)
    set_option(new_name, cs_options)
    # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time, modify_total_duration,
    #                            downloading_prohibition=True)
    simulation.run_simulation(
        name=new_name,
        simulation_type="extended",
        modify_pattern_start_time=modify_pattern_start_time,
        modify_total_duration=modify_total_duration,
        modify_valve_opening=modify_valve_opening,
        scheme_type="valve_close_Analysis",
        scheme_name=scheme_name,
    )
    # step 3. restore the base model
    # for valve in valves:
    #     execute_undo(name)
    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)
    # return result


############################################################
# flushing analysis 03
# Pipe_Flushing_Analysis(prj_name,date_time, Valve_id_list, Drainage_Node_Id, Flushing_flow[opt], Flushing_duration[opt])->out_file:string
############################################################
def flushing_analysis(
    name: str,
    modify_pattern_start_time: str,
    modify_total_duration: int = 900,
    modify_valve_opening: dict[str, float] = None,
    drainage_node_ID: str = None,
    flushing_flow: float = 0,
    scheme_name: str = None,
) -> None:
    """
    管道冲洗模拟
    :param name: 模型名称，数据库中对应的名字
    :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
    :param modify_total_duration: 模拟总历时，秒
    :param modify_valve_opening: dict中包含多个阀门开启度，str为阀门的id，float为修改后的阀门开启度
    :param drainage_node_ID: 冲洗排放口所在节点ID
    :param flushing_flow: 冲洗水量，传入参数单位为m3/h
    :param scheme_name: 方案名称
    :return:
    """
    scheme_detail: dict = {
        "duration": modify_total_duration,
        "valve_opening": modify_valve_opening,
        "drainage_node_ID": drainage_node_ID,
        "flushing_flow": flushing_flow,
    }
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"flushing_Anal_{name}"
    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    # if is_project_open(name):
    #     close_project(name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(name + "_template", new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Opening Database."
    )
    open_project(new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Database Loading OK."
    )
    if not is_junction(new_name, drainage_node_ID):
        return "Wrong Drainage node type"
    # step 1. change the valves status to 'closed'
    # for valve, valve_k in zip(valves, valves_k):
    #     cs=ChangeSet()
    #     status=get_status(new_name,valve)
    #     # status['status']='CLOSED'
    #     if valve_k == 0:
    #         status['status'] = 'CLOSED'
    #     elif valve_k < 1:
    #         status['status'] = 'OPEN'
    #         status['setting'] = 0.1036 * pow(valve_k, -3.105)
    #     cs.append(status)
    #     set_status(new_name,cs)
    options = get_option(new_name)
    units = options["UNITS"]
    # step 2. set the emitter coefficient of drainage node or add flush flow to the drainage node
    # 新建 pattern
    time_option = get_time(new_name)
    hydraulic_step = time_option["HYDRAULIC TIMESTEP"]
    secs = from_clock_to_seconds_2(hydraulic_step)
    cs_pattern = ChangeSet()
    pt = {}
    factors = []
    tmp_duration = modify_total_duration
    while tmp_duration > 0:
        factors.append(1.0)
        tmp_duration = tmp_duration - secs
    pt["id"] = "flushing_pt"
    pt["factors"] = factors
    cs_pattern.append(pt)
    add_pattern(new_name, cs_pattern)
    # 为 emitter_demand 添加新的 pattern
    emitter_demand = get_demand(new_name, drainage_node_ID)
    cs = ChangeSet()
    if flushing_flow > 0:
        if units == "LPS":
            emitter_demand["demands"].append(
                {
                    "demand": flushing_flow / 3.6,
                    "pattern": "flushing_pt",
                    "category": None,
                }
            )
        elif units == "CMH":
            emitter_demand["demands"].append(
                {"demand": flushing_flow, "pattern": "flushing_pt", "category": None}
            )
        cs.append(emitter_demand)
        set_demand(new_name, cs)
    else:
        pipes = get_node_links(new_name, drainage_node_ID)
        flush_diameter = 50
        for pipe in pipes:
            d = get_pipe(new_name, pipe)["diameter"]
            if flush_diameter < d:
                flush_diameter = d
        flush_diameter /= 1000
        emitter_coeff = (
            0.65 * 3.14 * (flush_diameter * flush_diameter / 4) * sqrt(19.6) * 1000
        )  # 全开口面积作为coeff

        old_emitter = get_emitter(new_name, drainage_node_ID)
        if old_emitter != None:
            old_emitter["coefficient"] = emitter_coeff  # 爆管的emitter coefficient设置
        else:
            old_emitter = {"junction": drainage_node_ID, "coefficient": emitter_coeff}
        new_emitter = ChangeSet()
        new_emitter.append(old_emitter)
        set_emitter(new_name, new_emitter)
    # step 3. run simulation
    # 涉及关阀计算，可能导致关阀后仍有流量，改为压力驱动PDA
    options = get_option(new_name)
    options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA
    options["REQUIRED PRESSURE"] = "20.0000"
    cs_options = ChangeSet()
    cs_options.append(options)
    set_option(new_name, cs_options)
    # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time, modify_total_duration,
    #                            downloading_prohibition=True)
    simulation.run_simulation(
        name=new_name,
        simulation_type="extended",
        modify_pattern_start_time=modify_pattern_start_time,
        modify_total_duration=modify_total_duration,
        modify_valve_opening=modify_valve_opening,
        scheme_type="flushing_analysis",
        scheme_name=scheme_name,
    )
    # step 4. restore the base model
    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)
    # return result
    # 存储方案信息到 PG 数据库
    store_scheme_info(
        name=name,
        scheme_name=scheme_name,
        scheme_type="flushing_analysis",
        username="admin",
        scheme_start_time=modify_pattern_start_time,
        scheme_detail=scheme_detail,
    )


############################################################
# Contaminant simulation 04
#
############################################################
def contaminant_simulation(
    name: str,
    modify_pattern_start_time: str,  # 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
    modify_total_duration: int,  # 模拟总历时，秒
    source: str,  # 污染源节点ID
    concentration: float,  # 污染源浓度，单位mg/L
    scheme_name: str = None,
    source_pattern: str = None,  # 污染源时间变化模式名称
) -> None:
    """
    污染模拟
    :param name: 模型名称，数据库中对应的名字
    :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
    :param modify_total_duration: 模拟总历时，秒
    :param source: 污染源所在的节点ID
    :param concentration: 污染源位置处的浓度，单位mg/L。默认的污染模拟setting为SOURCE_TYPE_CONCEN（改为SOURCE_TYPE_SETPOINT）
    :param source_pattern: 污染源的时间变化模式，若不传入则默认以恒定浓度持续模拟，时间长度等于duration;
            若传入，则格式为{1.0,0.5,1.1}等系数列表pattern_step模拟等于模型的hydraulic time step
    :param scheme_name: 方案名称
    :return:
    """
    scheme_detail: dict = {
        "source": source,
        "concentration": concentration,
        "duration": modify_total_duration,
        "pattern": source_pattern,
    }
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"contaminant_Sim_{name}"
    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    # if is_project_open(name):
    #     close_project(name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(name + "_template", new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Opening Database."
    )
    open_project(new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Database Loading OK."
    )
    dic_time = get_time(new_name)
    dic_time["QUALITY TIMESTEP"] = "0:05:00"
    cs = ChangeSet()
    cs.operations.append(dic_time)
    set_time(new_name, cs)  # set QUALITY TIMESTEP
    time_option = get_time(new_name)
    hydraulic_step = time_option["HYDRAULIC TIMESTEP"]
    secs = from_clock_to_seconds_2(hydraulic_step)
    operation_step = 0
    # step 1. set duration
    if modify_total_duration == None:
        modify_total_duration = secs
    # step 2. set pattern
    if source_pattern != None:
        pt = get_pattern(new_name, source_pattern)
        if len(pt) == 0:
            str_response = str("cant find source_pattern")
            return str_response
    else:
        cs_pattern = ChangeSet()
        pt = {}
        factors = []
        tmp_duration = modify_total_duration
        while tmp_duration > 0:
            factors.append(1.0)
            tmp_duration = tmp_duration - secs
        pt["id"] = "contam_pt"
        pt["factors"] = factors
        cs_pattern.append(pt)
        add_pattern(new_name, cs_pattern)
        operation_step += 1
    # step 3. set source/initial quality
    # source quality
    cs_source = ChangeSet()
    source_schema = {
        "node": source,
        "s_type": SOURCE_TYPE_SETPOINT,
        "strength": concentration,
        "pattern": pt["id"],
    }
    cs_source.append(source_schema)
    source_node = get_source(new_name, source)
    if len(source_node) == 0:
        add_source(new_name, cs_source)
    else:
        set_source(new_name, cs_source)
    dict_demand = get_demand(new_name, source)
    for demands in dict_demand["demands"]:
        dict_demand["demands"][dict_demand["demands"].index(demands)]["demand"] = -1
        dict_demand["demands"][dict_demand["demands"].index(demands)]["pattern"] = None
    cs = ChangeSet()
    cs.append(dict_demand)
    set_demand(new_name, cs)  # set inflow node
    # # initial quality
    # dict_quality = get_quality(new_name, source)
    # dict_quality['quality'] = concentration
    # cs = ChangeSet()
    # cs.append(dict_quality)
    # set_quality(new_name, cs)
    operation_step += 1
    # step 4 set option of quality to chemical
    opt = get_option(new_name)
    opt["QUALITY"] = OPTION_QUALITY_CHEMICAL
    cs_option = ChangeSet()
    cs_option.append(opt)
    set_option(new_name, cs_option)
    operation_step += 1
    # step 5. run simulation
    # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time,  modify_total_duration,
    #                            downloading_prohibition=True)
    simulation.run_simulation(
        name=new_name,
        simulation_type="extended",
        modify_pattern_start_time=modify_pattern_start_time,
        modify_total_duration=modify_total_duration,
        scheme_type="contaminant_analysis",
        scheme_name=scheme_name,
    )

    # for i in range(1,operation_step):
    #     execute_undo(name)
    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)
    # 存储方案信息到 PG 数据库
    store_scheme_info(
        name=name,
        scheme_name=scheme_name,
        scheme_type="contaminant_analysis",
        username="admin",
        scheme_start_time=modify_pattern_start_time,
        scheme_detail=scheme_detail,
    )


############################################################
# age analysis 05   ***水龄模拟目前还没和实时模拟打通，不确定是否需要，先不要使用***
############################################################


def age_analysis(
    name: str, modify_pattern_start_time: str, modify_total_duration: int = 900
) -> None:
    """
    水龄模拟
    :param name: 模型名称，数据库中对应的名字
    :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
    :param modify_total_duration: 模拟总历时，秒
    :return:
    """
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"age_Anal_{name}"
    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    # if is_project_open(name):
    #     close_project(name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(name + "_template", new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Opening Database."
    )
    open_project(new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Database Loading OK."
    )
    # step 1. run simulation

    result = run_simulation_ex(
        new_name,
        "realtime",
        modify_pattern_start_time,
        modify_total_duration,
        downloading_prohibition=True,
    )
    # step 2. restore the base model status
    # execute_undo(name) #有疑惑
    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)
    output = Output("./temp/{}.db.out".format(new_name))
    # element_name = output.element_name()
    # node_name = element_name['nodes']
    # link_name = element_name['links']
    nodes_age = []
    node_result = output.node_results()
    for node in node_result:
        nodes_age.append(node["result"][-1]["quality"])
    links_age = []
    link_result = output.link_results()
    for link in link_result:
        links_age.append(link["result"][-1]["quality"])
    age_result = {"nodes": nodes_age, "links": links_age}
    # age_result = {'nodes': nodes_age, 'links': links_age, 'nodeIDs': node_name, 'linkIDs': link_name}
    return json.dumps(age_result)


############################################################
# pressure regulation 06
############################################################


def pressure_regulation(
    name: str,
    modify_pattern_start_time: str,
    modify_total_duration: int = 900,
    modify_tank_initial_level: dict[str, float] = None,
    modify_fixed_pump_pattern: dict[str, list] = None,
    modify_variable_pump_pattern: dict[str, list] = None,
    scheme_name: str = None,
) -> None:
    """
    区域调压模拟，用来模拟未来15分钟内，开关水泵对区域压力的影响
    :param name: 模型名称，数据库中对应的名字
    :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00'
    :param modify_total_duration: 模拟总历时，秒
    :param modify_tank_initial_level: dict中包含多个水塔，str为水塔的id，float为修改后的initial_level
    :param modify_fixed_pump_pattern: dict中包含多个水泵模式，str为工频水泵的id，list为修改后的pattern
    :param modify_variable_pump_pattern: dict中包含多个水泵模式，str为变频水泵的id，list为修改后的pattern
    :param scheme_name: 模拟方案名称
    :return:
    """
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"pressure_regulation_{name}"
    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    # if is_project_open(name):
    #     close_project(name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(name + "_template", new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Opening Database."
    )
    open_project(new_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Database Loading OK."
    )
    # 全部关泵后，压力计算不合理，改为压力驱动PDA
    options = get_option(new_name)
    options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA
    options["REQUIRED PRESSURE"] = "15.0000"
    cs_options = ChangeSet()
    cs_options.append(options)
    set_option(new_name, cs_options)
    # result = run_simulation_ex(name=new_name,
    #                            simulation_type='realtime',
    #                            start_datetime=start_datetime,
    #                            duration=900,
    #                            pump_control=pump_control,
    #                            tank_initial_level_control=tank_initial_level_control,
    #                            downloading_prohibition=True)
    simulation.run_simulation(
        name=new_name,
        simulation_type="extended",
        modify_pattern_start_time=modify_pattern_start_time,
        modify_total_duration=modify_total_duration,
        modify_tank_initial_level=modify_tank_initial_level,
        modify_fixed_pump_pattern=modify_fixed_pump_pattern,
        modify_variable_pump_pattern=modify_variable_pump_pattern,
        scheme_type="pressure_regulation",
        scheme_name=scheme_name,
    )
    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)
    # return result
