import json
from datetime import datetime
from math import pi

import pytz

from app.algorithms.simulation.runner import run_simulation_ex
from app.infra.epanet.epanet import Output
from app.services.tjnetwork import (
    close_project,
    copy_project,
    delete_project,
    get_pipe,
    get_tank,
    have_project,
    is_project_open,
    open_project,
)


############################################################
# project management 07  ***暂时不使用，与业务需求无关***
############################################################


def project_management(
    prj_name,
    start_datetime,
    pump_control,
    tank_initial_level_control=None,
    region_demand_control=None,
) -> str:
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"project_management_{prj_name}"
    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    # if is_project_open(prj_name):
    #     close_project(prj_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(prj_name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(prj_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."
    )
    result = run_simulation_ex(
        name=new_name,
        simulation_type="realtime",
        start_datetime=start_datetime,
        duration=86400,
        pump_control=pump_control,
        tank_initial_level_control=tank_initial_level_control,
        region_demand_control=region_demand_control,
        downloading_prohibition=True,
    )
    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)
    return result


############################################################
# scheduling analysis 08   ***暂时不使用，与业务需求无关***
############################################################


def scheduling_simulation(
    prj_name, start_time, pump_control, tank_id, water_plant_output_id, time_delta=300
) -> str:
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"scheduling_{prj_name}"

    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    # if is_project_open(prj_name):
    #     close_project(prj_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(prj_name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(prj_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."
    )

    run_simulation_ex(
        new_name, "realtime", start_time, duration=0, pump_control=pump_control
    )

    if not is_project_open(new_name):
        open_project(new_name)

    tank = get_tank(new_name, tank_id)  # 水塔信息
    tank_floor_space = pi * pow(tank["diameter"] / 2, 2)  # 水塔底面积(m^2)
    tank_init_level = tank["init_level"]  # 水塔初始水位(m)
    tank_pipes_id = tank["links"]  # pipes list

    tank_pipe_flow_direction = (
        {}
    )  # 管道流向修正系数, 水塔为下游节点时为1, 水塔为上游节点时为-1
    for pipe_id in tank_pipes_id:
        if get_pipe(new_name, pipe_id)["node2"] == tank_id:  # 水塔为下游节点
            tank_pipe_flow_direction[pipe_id] = 1
        else:
            tank_pipe_flow_direction[pipe_id] = -1

    output = Output("./temp/{}.db.out".format(new_name))

    node_results = (
        output.node_results()
    )  # [{'node': str, 'result': [{'pressure': float}]}]
    water_plant_output_pressure = 0
    for node_result in node_results:
        if node_result["node"] == water_plant_output_id:  # 水厂出水压力(m)
            water_plant_output_pressure = node_result["result"][-1]["pressure"]
    water_plant_output_pressure /= 100  # 预计水厂出水压力(Mpa)

    pipe_results = output.link_results()  # [{'link': str, 'result': [{'flow': float}]}]
    tank_inflow = 0
    for pipe_result in pipe_results:
        for pipe_id in tank_pipes_id:  # 遍历与水塔相连的管道
            if pipe_result["link"] == pipe_id:  # 水塔入流流量(L/s)
                tank_inflow += (
                    pipe_result["result"][-1]["flow"]
                    * tank_pipe_flow_direction[pipe_id]
                )
    tank_inflow /= 1000  # 水塔入流流量(m^3/s)
    tank_level_delta = tank_inflow * time_delta / tank_floor_space  # 水塔水位改变值(m)
    tank_level = tank_init_level + tank_level_delta  # 预计水塔水位(m)

    simulation_results = {
        "water_plant_output_pressure": water_plant_output_pressure,
        "tank_init_level": tank_init_level,
        "tank_level": tank_level,
    }

    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)

    return json.dumps(simulation_results)


def daily_scheduling_simulation(
    prj_name, start_time, pump_control, reservoir_id, tank_id, water_plant_output_id
) -> str:
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Analysis."
    )
    new_name = f"daily_scheduling_{prj_name}"

    if have_project(new_name):
        if is_project_open(new_name):
            close_project(new_name)
        delete_project(new_name)
    # if is_project_open(prj_name):
    #     close_project(prj_name)
    print(
        datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S")
        + " -- Start Copying Database."
    )
    # CopyProjectEx()(prj_name, new_name,
    #                 ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table'])
    copy_project(prj_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."
    )

    run_simulation_ex(
        new_name, "realtime", start_time, duration=86400, pump_control=pump_control
    )

    if not is_project_open(new_name):
        open_project(new_name)

    output = Output("./temp/{}.db.out".format(new_name))

    node_results = (
        output.node_results()
    )  # [{'node': str, 'result': [{'pressure': float, 'head': float}]}]
    water_plant_output_pressure = []
    reservoir_level = []
    tank_level = []
    for node_result in node_results:
        if node_result["node"] == water_plant_output_id:
            for result in node_result["result"]:
                water_plant_output_pressure.append(
                    result["pressure"] / 100
                )  # 水厂出水压力(Mpa)
        elif node_result["node"] == reservoir_id:
            for result in node_result["result"]:
                reservoir_level.append(result["head"] - 250.35)  # 清水池液位(m)
        elif node_result["node"] == tank_id:
            for result in node_result["result"]:
                tank_level.append(result["pressure"])  # 调节池液位(m)

    simulation_results = {
        "water_plant_output_pressure": water_plant_output_pressure,
        "reservoir_level": reservoir_level,
        "tank_level": tank_level,
    }

    if is_project_open(new_name):
        close_project(new_name)
    delete_project(new_name)

    return json.dumps(simulation_results)
