import copy
import os
import random

from yangke.performance.iapws97 import get_h_by_pt
from yangke.common.config import logger
from yangke.common.fileOperate import write_excel, pd_set_na, read_excel
from yangke.sis.BeiJingShenHua.tags import TagsRead, TagsWrite
from yangke.sis.dll_file import read_data, get_tag_value, init_write_sis, init_dbp_api
import pandas as pd
from yangke.sis.BeiJingShenHua.tags import get_pump_type_by_int
from yangke.base import is_number

ip = "10.2.128.168"
port = "12084"
user = "admin"
passwd = "admin"


def filter_(df, tag, value_range):
    """
    从df中删除参数不在范围内的数据，示例
    filter_(his_value, "#1电功率", [200,300])  # 只保留电功率在200~300之间的行
    filter_(his_value, "#1电功率", [200,None]) # 只保留电功率在200以上的行
    filter_(his_value, "#1电功率", [None,100])  # 只保留电功率在100以下的行
    """
    min_value = value_range[0]
    max_value = value_range[1]
    if min_value is not None:
        df = df[df[tag] >= min_value]
    if max_value is not None:
        df = df[df[tag] <= max_value]
    return df


def get_history(tags, des, months=12, days=0):
    """
    从RDBProxy代理服务器上导出历史数据，如果导出数据的时标是1970年，请检查tags标签是否正确

    tags: list类型，导出测点的标签，需要与DCS系统上测点的KKS码或标签名一致
    des: list类型，导出测点的描述，可以自定义，用于注释导出的测点，如果传入该参数，则长度必须与tags相同
    month: 到处历史数据的月份
    """
    from datetime import datetime, timedelta

    now = datetime.now()
    if months != 0:
        for i in range(12):
            logger.debug(f"正在导出第{i + 1}个月的历史数据...")
            api = init_dbp_api(ip=ip, port=port, user=user, password=passwd)
            his_value = api.get_his_value(tags=tags, tags_description=des,
                                          start_time=now - timedelta(days=30 * (i + 1), hours=0),
                                          end_time=now - timedelta(days=30 * i, hours=0), time_interval=60)
            # his_value = his_value.set_index("DateTime").rolling(window=10).mean()
            # his_value.dropna(how="any", inplace=True)
            # his_value.drop(his_value.tail(10).index, inplace=True)  # 删掉最后十行数据

            his_value.to_csv(f"origin_{i + 1}.csv", index=None)  # his_value为原始数据，不删除任何时间的数据
    else:
        api = init_dbp_api(ip=ip, port=port, user=user, password=passwd)
        his_value = api.get_his_value(tags=tags, tags_description=des,
                                      start_time=now - timedelta(days=days, hours=0),
                                      end_time=now - timedelta(days=0, hours=0), time_interval=60)
        # his_value = his_value.set_index("DateTime").rolling(window=10).mean()
        # his_value.dropna(how="any", inplace=True)
        # his_value.drop(his_value.tail(10).index, inplace=True)  # 删掉最后十行数据

        his_value.to_csv(f"最近{days}天历史数据.csv", index=None)  # his_value为原始数据，不删除任何时间的数据


def deal_data(files=None, work_folder=None):
    if files is None:
        files = ["origin_1.csv", "origin_2.csv", "origin_3.csv", "origin_4.csv",
                 "origin_5.csv", "origin_6.csv", "origin_7.csv", "origin_8.csv",
                 "origin_9.csv", "origin_11.csv",
                 ]

    output_data = {}
    for file in files:
        logger.debug(f"处理{file=}")
        if work_folder is not None:
            file = os.path.join(work_folder, file)
        df = pd.read_csv(file)
        his = df.copy()
        df.set_index("DateTime", inplace=True)
        df.index = pd.DatetimeIndex(df.index)  # 将索引类型转换为DatetimeIndex以便可以使用按时间的插值方法
        # df = df.iloc[0:40]
        df["大气压力"] = df["大气压力"] / 10000  # MPa
        # 将大气压力低于0.03MPa的行的数据全部置为np.nan，因为发现有时候DCS系统数据传输故障，时序数据库中数据全都为0
        pd_set_na(df, {"大气压力": {"<": 0.03}}, expand=True, axis=0)
        df = df.interpolate(method="time")  # 31332
        df.drop(columns=["建议循泵运行方式", "建议风机运行方式", "最优运行方式下背压", "优化后机组节煤量",
                         "计量单元天然气流量1", "计量单元天然气流量2", "计量单元天然气流量3",
                         ], axis=1, inplace=True)
        for _fan_num in ["风机1电流", "风机2电流", "风机3电流", "风机4电流", "风机5电流", "风机6电流", "风机7电流",
                         "风机8电流",
                         "大泵1电流", "大泵2电流", "小高速3电流", "小高速4电流", "小低速3电流", "小低速4电流"]:
            df[_fan_num] = df[_fan_num].apply(lambda x: 0 if x <= 10 else x)
            df[_fan_num] = df[_fan_num].apply(lambda x: 1 if x > 10 else x)
        df["机力塔数量"] = df["风机1电流"] + df["风机2电流"] + df["风机3电流"] + df["风机4电流"] + \
                           df["风机5电流"] + df["风机6电流"] + df["风机7电流"] + df["风机8电流"]
        df["机力塔数量"] = df["机力塔数量"].apply(lambda x: int(x))
        df["当前大泵数量"] = df["大泵1电流"] + df["大泵2电流"]
        df["当前高速泵数量"] = df["小高速3电流"] + df["小高速3电流"]
        df["当前低速泵数量"] = df["小低速3电流"] + df["小低速4电流"]
        df.drop(columns=["风机1电流", "风机2电流", "风机3电流", "风机4电流", "风机5电流", "风机6电流", "风机7电流",
                         "风机8电流",
                         "大泵1电流", "大泵2电流", "小高速3电流", "小高速4电流", "小低速3电流", "小低速4电流"], axis=1,
                inplace=True)

        df["循泵方式"] = df["当前大泵数量"] * 100 + df["当前高速泵数量"] * 10 + df["当前低速泵数量"]
        df["循泵方式"] = df["循泵方式"].apply(lambda x: get_pump_type_by_int(int(x)))
        df.drop(columns=["当前大泵数量", "当前高速泵数量", "当前低速泵数量"], axis=1, inplace=True)

        df["主汽门前压力"] = df["主汽门前压力"] + df["大气压力"]
        df["高排压力"] = df["高排压力"] + df["大气压力"]
        df["中压主汽门前压力"] = df["中压主汽门前压力"] + df["大气压力"]
        df["低压蒸汽压力1"] = df["低压蒸汽压力1"] + df["大气压力"]
        df["低压蒸汽压力2"] = df["低压蒸汽压力2"] + df["大气压力"]
        df["热井出水压力"] = df["热井出水压力"] + df["大气压力"]

        df["主蒸汽焓"] = df.apply(lambda x: get_h_by_pt(x["主汽门前压力"], x["主汽门前温度"]), axis=1)
        df["高排焓"] = df.apply(lambda x: get_h_by_pt(x["高排压力"], x["高排温度"]), axis=1)
        df["主蒸汽流量"] = df["高压蒸汽流量1号炉"] + df["高压蒸汽流量2号炉"] + df["高压蒸汽减温水流量1号炉"] + df[
            "高压蒸汽减温水流量2号炉"]
        df["高压缸进汽能量"] = df["主蒸汽流量"] * df["主蒸汽焓"] * 1000
        合缸处漏气量 = 17.962
        df["高排流量"] = df["主蒸汽流量"] - 合缸处漏气量
        df["高排能量"] = df["高排焓"] * df["高排流量"] * 1000
        df["中压进汽流量"] = df["中压给水流量1号炉"] + df["中压给水流量2号炉"] + df["再热减温水流量1"] + \
                             df["再热减温水流量2"] + df["高排流量"] - df["FGH流量1号炉"] - df["FGH流量2号炉"]
        df["中压进汽焓"] = df.apply(lambda x: get_h_by_pt(x["中压主汽门前压力"], x["中压主汽门前温度"]),
                                    axis=1)
        df["中压进汽能量"] = df["中压进汽焓"] * df["中压进汽流量"] * 1000

        df.drop(columns=["主汽门前压力", "主汽门前温度", "高排压力", "高排温度", "主蒸汽焓", "高排焓", "主蒸汽流量",
                         "高排流量",
                         "中压给水流量1号炉", "中压给水流量2号炉", "再热减温水流量1", "再热减温水流量2", "FGH流量1号炉",
                         "FGH流量2号炉", "高压蒸汽减温水流量1号炉", "高压蒸汽减温水流量2号炉", "高压蒸汽流量1号炉",
                         "高压蒸汽流量2号炉", "中压主汽门前压力", "中压主汽门前温度", "燃机功率1", "燃机功率2"], axis=1,
                inplace=True)

        df["低压补汽能量1"] = df.apply(
            lambda x: get_h_by_pt(x["低压蒸汽压力1"], x["低压蒸汽温度1"]) * x["低压蒸汽流量1"] * 1000,
            axis=1)
        df["低压补汽能量2"] = df.apply(
            lambda x: get_h_by_pt(x["低压蒸汽压力2"], x["低压蒸汽温度2"]) * x["低压蒸汽流量2"] * 1000,
            axis=1)
        df["低压补汽能量"] = df["低压补汽能量1"] + df["低压补汽能量2"]

        df["热井出水流量"] = df["凝结水流量1号炉"] + df["凝结水流量2号炉"]
        df["热井出水焓"] = df.apply(lambda x: get_h_by_pt(x["热井出水压力"], x["热井出水温度"]), axis=1)
        df["热井出水能量"] = df["热井出水流量"] * df["热井出水焓"] * 1000

        df.drop(columns=["低压蒸汽压力1", "低压蒸汽温度1", "低压蒸汽流量1", "低压蒸汽压力2", "低压蒸汽温度2",
                         "低压蒸汽流量2",
                         "低压补汽能量1", "低压补汽能量2", "凝结水流量1号炉", "凝结水流量2号炉", "热井出水压力",
                         "热井出水温度", "热井出水流量", "热井出水焓", "中压进汽流量", "中压进汽焓"], axis=1,
                inplace=True)

        df["p"] = df["烟气热网加热器进水压力"] + df["大气压力"]
        df["热网加热器流量"] = df["烟气热网加热器进水流量"] / 2
        df["烟气换热量"] = df.apply(
            lambda x: (x["热网加热器流量"] * (get_h_by_pt(x["p"], x["烟气热网加热器供水温度1"]) - get_h_by_pt(x["p"], x[
                "烟气热网加热器进水温度1"]))
                       + x["热网加热器流量"] * (
                               get_h_by_pt(x["p"], x["烟气热网加热器供水温度2"]) - get_h_by_pt(x["p"], x[
                           "烟气热网加热器进水温度2"]))) * 1000,
            axis=1
        )

        df["供热能量"] = df["供热热量"] * 1000000 - df["烟气换热量"]
        df["轴功率"] = df["发电机有功功率_steam"] / 0.988 * 3600 * 1000
        df["凝汽器热负荷"] = df["高压缸进汽能量"] + df["中压进汽能量"] + df["低压补汽能量"] - df["高排能量"] - 18502790 \
                             - df["供热能量"] - df["轴功率"] - df["热井出水能量"]
        df["凝汽器热负荷"] = df["凝汽器热负荷"] / 3600 / 1000
        df.drop(columns=["供热热量", "供热能量", "发电机有功功率_steam", "轴功率", "高压缸进汽能量", "中压进汽能量",
                         "低压补汽能量", "高排能量", "供热能量", "热井出水能量", "大气压力", "热网加热器疏水流量1",
                         "热网加热器疏水流量2", "当前循泵运行方式", "当前风机运行方式", "凝汽器循环水进水温度1",
                         "凝汽器循环水进水温度2", "烟气热网加热器进水流量", "烟气热网加热器进水压力",
                         "烟气热网加热器进水温度1",
                         "烟气热网加热器供水温度1", "烟气热网加热器进水温度2", "烟气热网加热器供水温度2",
                         "热网加热器流量", "烟气换热量", "烟气热网加热器进水流量",
                         ], axis=1, inplace=True, errors='ignore')

        df["凝汽器热负荷"] = df["凝汽器热负荷"].rolling(window=10).mean()  # 因为凝汽器热负荷参数锯齿状波动严重，取移动平均值
        df["环境湿度"] = df["环境湿度"].rolling(10).mean()
        df = df[["全厂总功率", "凝汽器热负荷", "环境温度", "环境湿度", "循泵方式", "机力塔数量", "当前背压"]]
        df = df.copy()
        df.drop(df.head(9).index, inplace=True)  # 删除前10行

        # 检测如果冷端运行方式改变，则删除后续的20分钟数据
        time_section = 20
        is_steady = ["F-top19"] * (time_section - 1)  # 前19行认为不稳定
        for row_idx in range(time_section, df.shape[0] + 1):
            _p = df.iloc[row_idx - time_section: row_idx][
                "循泵方式"]  # df.iloc[0, 20]["循泵方式"].all() -> df.iloc[19]=True
            _f = df.iloc[row_idx - time_section: row_idx]["机力塔数量"]
            if (_p.values == _p.values[0]).all() and (_f.values == _f.values[0]).all():
                is_steady.append("T")
            else:
                is_steady.append("F-冷端方式调整")

        # 考虑到需要保持时间的连续性，此处先标记该行数据需要删除，而不能直接对数据进行删除，否则会影响后续的稳定性条件判断

        # 检测功率如果波动超过20分钟内功率波动超过10MW，则删除数据
        for row_idx in range(time_section, df.shape[0] + 1):
            _p = df.iloc[row_idx - time_section:row_idx]
            if _p["凝汽器热负荷"].max() - _p["凝汽器热负荷"].min() > 10:
                is_steady[row_idx - 1] = "F-热负荷波动"  # 166
                # logger.debug(f"{row_idx=}, 热负荷max={_p['凝汽器热负荷'].max()},min={_p['凝汽器热负荷'].min()}")
            if _p["环境温度"].max() - _p["环境温度"].min() > 5:
                is_steady[row_idx - 1] = "F-环境温度波动"  # 39101
                # logger.debug(f"{row_idx=},环境温度max={_p['环境温度'].max()},min={_p['环境温度'].min()}")
            if _p["环境湿度"].max() - _p["环境湿度"].min() > 10:
                is_steady[row_idx - 1] = "F-环境湿度波动"  # 97
                # logger.debug(f"{row_idx=},环境湿度max={_p['环境湿度'].max()},min={_p['环境湿度'].min()}")

        df["steady"] = is_steady

        df = df[df["steady"].apply(lambda x: x.startswith("T"))]
        output_data.update({os.path.basename(file).split(".")[0]: df})

    write_excel("历史数据库.xlsx", output_data, index=True)


def load_history_file(file):
    """
    加载历史数据文件

    :param file:
    :return:
    """
    df = pd.DataFrame()
    if os.path.exists(file):
        if file.endswith(".csv"):
            df = pd.read_csv(file)
        else:
            df = read_excel(file, need_merge=True, index_col=0)
    return df


def find_condition(df, unit_condition, cold_condition: dict = None, auto_loose=False):
    """
    查找符合条件的历史工况，返回满足条件的历史数据及历史数据的统计平均值
    示例：
    df, df_mean = find_condition(file="历史数据库.xlsx",
                   unit_condition=[("凝汽器热负荷", 360, "1%"), ("环境温度", 27, "±2"), ("环境湿度", 50, "±10")],
                   cold_condition={"循泵方式": 'B', "机力塔数量": 8}
                   )

    :param auto_loose: 是否自动放宽条件限制，如果为True，当没有找到符合条件的工况时，会自动放宽允许的偏差为原来的两倍再次尝试，直到找到
    :param df: 历史数据dataframe，csv或者xlsx文件
    :param unit_condition: 机组的运行状态参数
    :param cold_condition: 冷端设备运行状态参数
    :return:
    """
    origin_df = df.copy()

    for title, val in cold_condition.items():
        df = df[df[title] == val]
    if df.shape[0] == 0:
        logger.debug(f"历史上不存在{cold_condition}的冷端运行方式")
        return None
    for item in unit_condition:
        title, val, tolerance = item
        if is_number(val):
            if is_number(tolerance):
                val_min = val * (1 - tolerance)
                val_max = val * (1 + tolerance)
            elif tolerance.endswith("%"):
                tolerance = float(tolerance.replace("%", "")) / 100
                val_min = val * (1 - tolerance)
                val_max = val * (1 + tolerance)
            elif tolerance.startswith("±"):
                tolerance = float(tolerance.replace("±", ""))
                val_min = val - tolerance
                val_max = val + tolerance
            df = df[df[title] < val_max]
            df = df[df[title] > val_min]
    df = df.copy()
    if df.shape[0] < 5:
        if auto_loose:
            new_condition = []
            for item in unit_condition:
                title, val, tolerance = item
                if is_number(tolerance):
                    tolerance = tolerance * 2
                elif tolerance.endswith("%"):
                    tolerance = float(tolerance.replace("%", "")) / 100
                    tolerance = f"{tolerance * 200}%"
                elif tolerance.startswith("±"):
                    tolerance = float(tolerance.replace("±", ""))
                    tolerance = f"±{tolerance * 2}"
                new_condition.append((title, val, tolerance))
            logger.debug(f"历史数据中满足条件的工况个数为{df.shape[0]}，放宽条件限制为：{new_condition}")
            return find_condition(origin_df, new_condition, cold_condition, auto_loose)
    else:
        logger.debug(df)
        logger.debug(f"满足条件工况的平均参数为：{df.mean(numeric_only=True)}")
    return df


if __name__ == "__main__":
    des1 = TagsRead.get_keys()
    tags1 = TagsRead.get_values()

    des2 = TagsWrite.get_keys()
    tags2 = TagsWrite.get_values()

    tags1.extend(tags2)
    des1.extend(des2)
    # get_history(tags1, des1, months=12, days=0)
    # deal_data(work_folder=r"D:\User")
    df = find_condition(file="历史数据库.xlsx",
                        unit_condition=[("凝汽器热负荷", 360, "1%"), ("环境温度", 33, "±2"), ("环境湿度", 50, "±10")],
                        cold_condition={"循泵方式": 'B', "机力塔数量": 8},
                        auto_loose=True
                        )
    logger.debug(df.mean(numeric_only=True)["当前背压"])
