# -*- coding:utf-8 -*-
#
# Author:jing
# Date: 2020/7/9
import time
import json
from dataclasses import fields
import re
from pot_libs.settings import SETTING
from datetime import datetime

from unify_api.modules.common.procedures.points import get_meter_by_point_new15
from unify_api.modules.common.service.td_engine_service import \
    get_td_engine_data

from pot_libs.aredis_util.aredis_utils import RedisUtils
from pot_libs.es_util.es_query import EsQuery
from pot_libs.es_util.es_utils import EsUtil
from pot_libs.sanic_api import summary, description, examples
from pot_libs.logger import log
from pot_libs.utils.exc_util import ParamException, DBException, BusinessException
from pot_libs.utils.pendulum_wrapper import my_pendulum
from unify_api.modules.common.components.common_cps import CidPointsReq
from unify_api.modules.common.procedures import health_score
from unify_api.modules.electric.service.electric_service import \
    elec_current_storeys_service, qual_current_storeys_service, \
    elec_card_level_service, qual_current_level_service, elec_index_service, \
    elec_index_service_new15, elec_current_service_new15, get_sdu_i_and_u
from unify_api.utils import time_format
from unify_api import constants
from unify_api.modules.electric.procedures.electric_util import (
    get_wiring_type, get_wiring_type_new15,
    add_random_change,
)

from pot_libs.common.components.query import PageRequest, Range, Equal, Filter
from unify_api.modules.electric.components.electric import (
    ElecHistoryResponse,
    ElecCurrentResponse,
    qual_current_example,
    QualHistoryResponse,
    qual_history__example,
    ThreePhaseImbalance,
    QualCurrentResponse,
    VoltageHarmonicRate,
    CurrentHarmonicRate,
    VoltageDev,
    Power,
    U,
    I,
    elec_current_example,
    ElecIndexResponse,
    elec_index_example,
    elec_history_example,
    VoltageHarmonic,
    CurrentHarmonic, EcsReq, EscResp, QcsResp, EclResp, QclResp,
)
from unify_api.utils.request_util import filed_value_from_list
from unify_api.modules.electric.dao.electric_dao import get_qual_history_dao,\
    get_elec_history_dao

METERDATA_CURRENT_KEY = "meterdata_current"
METERDATA_CURRENT_HR_KEY = "meterdata_hr_current"


@summary("用电监测-实时监测-历史曲线")
@description("包含负载率、有功/无功、功率因素、电压、电流、频率曲线")
@examples(elec_history_example)
async def post_elec_history(req, body: PageRequest) -> ElecHistoryResponse:
    #  1.获取intervel和时间轴
    try:
        date_start = body.filter.ranges[0].start
        date_end = body.filter.ranges[0].end
    except:
        log.error("param error, ranges is NULL")
        raise ParamException(message="param error, ranges is NULL")

    try:
        intervel, slots = time_format.time_pick_transf(date_start, date_end)
    except:
        log.error("param error, date format error")
        raise ParamException(message="param error, date format error")

    point_id = filed_value_from_list(body.filter.equals, "point_id")

    if point_id <= 0 or not point_id:
        log.warning("param exception, equals is NULL, no point_id")
        raise ParamException(
            message="param exception, equals is NULL, no point_id")
    # return await elec_history_service(date_start, date_end, point_id,
    #                                   intervel, slots)
    return await elec_history_service_new15(date_start, date_end, point_id,
                                            intervel, slots)


async def elec_history_service(date_start, date_end, point_id, intervel,
                               slots):
    # 2.获取曲线数据
    # 2.1 起始时间分别转化为时间戳
    es_start_dt = my_pendulum.from_format(date_start, "YYYY-MM-DD HH:mm:ss")
    es_end_dt = my_pendulum.from_format(date_end, "YYYY-MM-DD HH:mm:ss")
    range = Range(field="quarter_time", start=es_start_dt, end=es_end_dt)
    equal = Equal(field="pid", value=point_id)
    filter = Filter(equals=[equal], ranges=[range], in_groups=[], keywords=[])
    page_request = PageRequest(page_size=1, page_num=1, sort=None,
                               filter=filter)

    ctnum, _ = await get_wiring_type(point_id)

    if ctnum not in [2, 3]:
        log.error(
            f"elec_index point_id={point_id} ctnum={ctnum} 找不到ctnum , 监测点已经拆除")
        # 这个实际上装置点已经拆除，无法获取到接表法，但是页面又可以选择, 只能给个默认值，但是不是根本解决办法，万一人家历史数据是二表法呢
        # 那么就给默认值吧，没办法了
        ctnum = 3

    query_body = EsQuery.aggr_history_new(
        page_request,
        interval=intervel,
        stats_items=[
            "lf_mean",
            "pttl_mean",
            "qttl_mean",
            "costtl_mean",
            "uab_mean",
            "ucb_mean",
            "ua_mean",
            "ub_mean",
            "uc_mean",
            "ia_mean",
            "ib_mean",
            "ic_mean",
            "freq_mean",
        ],
        histogram_field="quarter_time",
    )

    async with EsUtil() as es:
        es_results = await es.search_origin(body=query_body,
                                            index=constants.POINT_15MIN_INDEX)

    if ctnum == 2:
        stats_items = [
            "lf_mean",
            "pttl_mean",
            "qttl_mean",
            "costtl_mean",
            "uab_mean",
            "ucb_mean",
            "ia_mean",
            "ic_mean",
            "freq_mean",
        ]
    else:
        stats_items = [
            "lf_mean",
            "pttl_mean",
            "qttl_mean",
            "costtl_mean",
            "ua_mean",
            "ub_mean",
            "uc_mean",
            "ia_mean",
            "ib_mean",
            "ic_mean",
            "freq_mean",
        ]

    aggs_res = es_results.get("aggregations", {})
    data_buckets = aggs_res.get("aggs_name", {}).get("buckets", [])

    time_bucket_map = {i["key_as_string"]: i for i in data_buckets}
    print(
        f"post_elec_history slots={slots} _data = {list(time_bucket_map.keys())}, query_body={query_body}"
    )
    elec_data = {stats_item: [] for stats_item in stats_items}
    for slot in slots:
        if slot in time_bucket_map:
            for stats_item in stats_items:
                value = time_bucket_map[slot].get(stats_item, {}).get("avg")
                value = value if value is not None else ""
                elec_data[stats_item].append(value)
        else:
            for stats_item in stats_items:
                elec_data[stats_item].append("")

    # 识电U只有一项有数据,返回具体的项
    sdu_i = None
    sdu_u = None
    if ctnum == 2:
        u = U(uab=elec_data["uab_mean"], ucb=elec_data["ucb_mean"])
        i = I(ia=elec_data["ia_mean"], ic=elec_data["ic_mean"])
        if any(elec_data["uab_mean"]) and not any(elec_data["ucb_mean"]):
            sdu_i = "ia"
            sdu_u = "uab"
        if any(elec_data["ucb_mean"]) and not any(elec_data["uab_mean"]):
            sdu_i = "ic"
            sdu_u = "ucb"
    else:
        u = U(ua=elec_data["ua_mean"], ub=elec_data["ub_mean"],
              uc=elec_data["uc_mean"])
        i = I(ia=elec_data["ia_mean"], ib=elec_data["ib_mean"],
              ic=elec_data["ic_mean"])
        if (
                any(elec_data["ua_mean"])
                and not any(elec_data["ub_mean"])
                and not any(elec_data["uc_mean"])
        ):
            sdu_i = "ia"
            sdu_u = "ua"
        if (
                any(elec_data["ub_mean"])
                and not any(elec_data["ua_mean"])
                and not any(elec_data["uc_mean"])
        ):
            sdu_i = "ib"
            sdu_u = "ub"
        if (
                any(elec_data["uc_mean"])
                and not any(elec_data["ua_mean"])
                and not any(elec_data["ub_mean"])
        ):
            sdu_i = "ic"
            sdu_u = "uc"

    return ElecHistoryResponse(
        ctnum=ctnum,
        lf=elec_data["lf_mean"],
        power=Power(p=elec_data["pttl_mean"], q=elec_data["qttl_mean"]),
        costtl=elec_data["costtl_mean"],
        u=u,
        i=i,
        freq=elec_data["freq_mean"],
        time_slots=slots,
        sdu_i=sdu_i,
        sdu_u=sdu_u,
    )


async def elec_history_service_new15(start, end, pid, intervel, slots):
    ctnum = await get_wiring_type_new15(pid)
    if ctnum == 2:
        stats_items = [
            "lf_mean", "pttl_mean", "qttl_mean", "costtl_mean", "uab_mean",
            "ucb_mean", "ia_mean", "ic_mean", "freq_mean"
        ]
    else:
        ctnum = 3
        stats_items = [
            "lf_mean", "pttl_mean", "qttl_mean", "costtl_mean", "ua_mean",
            "ub_mean", "uc_mean", "ia_mean", "ib_mean", "ic_mean", "freq_mean"
        ]
    if intervel == 900:
        table_name = "point_15min_electric"
        date_format = "%%H:%%i"
    else:
        table_name = "point_1day_electric"
        date_format = "%%m-%%d"
    datas = await get_elec_history_dao(table_name, pid, start, end, date_format)
    datas = {data["date_time"]: data for data in datas}
    elec_data = {stats_item: [] for stats_item in stats_items}
    for slot in slots:
        if slot in datas.keys():
            for stats_item in stats_items:
                value = datas[slot].get(stats_item)
                value = value if value is not None else ""
                elec_data[stats_item].append(value)
        else:
            for stats_item in stats_items:
                elec_data[stats_item].append("")
    # 识电U只有一项有数据,返回具体的项
    sdu_i = None
    sdu_u = None
    if ctnum == 2:
        u = U(uab=elec_data["uab_mean"], ucb=elec_data["ucb_mean"])
        i = I(ia=elec_data["ia_mean"], ic=elec_data["ic_mean"])
        if any(elec_data["uab_mean"]) and not any(elec_data["ucb_mean"]):
            sdu_i, sdu_u = "ia", "uab"
        if any(elec_data["ucb_mean"]) and not any(elec_data["uab_mean"]):
            sdu_i, sdu_u = "ic", "ucb"
    else:
        u = U(ua=elec_data["ua_mean"], ub=elec_data["ub_mean"],
              uc=elec_data["uc_mean"])
        i = I(ia=elec_data["ia_mean"], ib=elec_data["ib_mean"],
              ic=elec_data["ic_mean"])
        if (
                any(elec_data["ua_mean"])
                and not any(elec_data["ub_mean"])
                and not any(elec_data["uc_mean"])
        ):
            sdu_i, sdu_u = "ia", "ua"
        if (
                any(elec_data["ub_mean"])
                and not any(elec_data["ua_mean"])
                and not any(elec_data["uc_mean"])
        ):
            sdu_i, sdu_u = "ib", "ub"
        if (
                any(elec_data["uc_mean"])
                and not any(elec_data["ua_mean"])
                and not any(elec_data["ub_mean"])
        ):
            sdu_i, sdu_u = "ic", "uc"
    return ElecHistoryResponse(
        ctnum=ctnum,
        lf=elec_data["lf_mean"],
        power=Power(p=elec_data["pttl_mean"], q=elec_data["qttl_mean"]),
        costtl=elec_data["costtl_mean"],
        u=u,
        i=i,
        freq=elec_data["freq_mean"],
        time_slots=slots,
        sdu_i=sdu_i,
        sdu_u=sdu_u,
    )


@summary("用电监测-实时监测-实时参数")
@examples(elec_current_example)
async def post_elec_current(req, body: PageRequest) -> ElecCurrentResponse:
    point_id = filed_value_from_list(body.filter.equals, "point_id")
    if point_id <= 0 or not point_id:
        log.warning("param exception, equals is NULL, no point_id")
        raise ParamException(
            message="param exception, equals is Ncount_infoULL, no point_id")
    try:
        time_str, res = await elec_current_service_new15(point_id)
    except Exception as e:
        log.error(f"post_elec_current elec_current_service_new15 error:"
                  f"{str(e)}")
        raise BusinessException(message=f"{str(e)}")
    return ElecCurrentResponse(
        real_time=time_str,
        **{
            k: v
            for k, v in res.items()
            if k in [field.name for field in fields(ElecCurrentResponse)]
        },
    )


async def post_elec_current_bak(req, body: PageRequest) -> ElecCurrentResponse:
    point_id = filed_value_from_list(body.filter.equals, "point_id")

    if point_id <= 0 or not point_id:
        log.warning("param exception, equals is NULL, no point_id")
        raise ParamException(
            message="param exception, equals is Ncount_infoULL, no point_id")

    ctnum, mid = await get_wiring_type(point_id)
    if ctnum not in [2, 3]:
        log.error(
            f"elec_index point_id={point_id} ctnum={ctnum} 找不到ctnum 装置已经拆除")

    if not mid:
        log.error(f"post_elec_current pid={point_id} 没有mid 装置已经被拆除")
        # 拆了，没数据，返回空
        return ElecCurrentResponse()
    try:
        now_ts = int(time.time())
        real_tt = now_ts
        res = None

        result = await RedisUtils().hget(METERDATA_CURRENT_KEY, mid)
        result2 = await RedisUtils().hget(METERDATA_CURRENT_HR_KEY, mid)
        if result and result2:
            res = json.loads(result)
            res2 = json.loads(result2)
            real1_tt = res.get("timestamp")
            real_tt = res2.get("timestamp")
            if (
                    real1_tt
                    and real_tt
                    and now_ts - real1_tt <= constants.REAL_EXP_TIME
                    and now_ts - real_tt <= constants.REAL_EXP_TIME
            ):
                for k in res2.keys():
                    if not k in res.keys():
                        res[k] = res2[k]
            else:
                log.info("1 realtime_elec_qual of mid %s is expired." % mid)
                res = None
                real_tt = now_ts

        elif result2:
            res = json.loads(result2)
            real_tt = res.get("timestamp")
            if real_tt and now_ts - real_tt <= constants.REAL_EXP_TIME:
                res = res
            else:
                log.info("2 realtime_elec_qual of mid %s is expired." % mid)
                res = None
                real_tt = now_ts

        elif result:
            res = json.loads(result)
            real_tt = res.get("timestamp")
            if real_tt and now_ts - real_tt <= constants.REAL_EXP_TIME:
                res = res
            else:
                log.info("3 realtime_elec_qual of mid %s is expired." % mid)
                res = None
                real_tt = now_ts

        else:
            log.error("realtime_elec_qual not exist")
        time_str = time_format.get_datetime_str(real_tt)
    except Exception as e:
        log.exception(e)
        raise DBException

    # 加些随机变化(防止数据一直不变化)
    if res:
        for k in res.keys():
            res[k] = add_random_change(res[k])
    else:
        log.error("realtime_elec_qual not exist")
        return ElecCurrentResponse()

    if not ctnum:
        # 如果已经拆掉了，还有报文，用报文中的ctnum
        ctnum = res.get("ctnum") or 3

    if "ctnum" in res:
        del res["ctnum"]

    # 识电U只有一项有数据,返回具体的项
    res["sdu_i"] = None
    res["sdu_u"] = None
    if "ia" in res and "ib" not in res and "ic" not in res:
        res["sdu_i"] = "ia"
        if ctnum == 3:
            res["sdu_u"] = "ua"
        if ctnum == 2:
            res["sdu_u"] = "uab"
    if "ib" in res and "ia" not in res and "ic" not in res:
        res["sdu_i"] = "ib"
        if ctnum == 3:
            res["sdu_u"] = "ub"
    if "ic" in res and "ia" not in res and "ib" not in res:
        res["sdu_i"] = "ic"
        if ctnum == 3:
            res["sdu_u"] = "uc"
        if ctnum == 2:
            res["sdu_u"] = "ucb"

    return ElecCurrentResponse(
        ctnum=ctnum,
        real_time=time_str,
        **{
            k: v
            for k, v in res.items()
            if k in [field.name for field in fields(ElecCurrentResponse)]
        },
    )


@summary("指标统计-指标统计-常规参数+电能质量")
@examples(elec_index_example)
async def post_elec_index(req, body: PageRequest) -> ElecIndexResponse:
    cid = req.json.get("cid")
    # 1. 获取point_id
    point_id = filed_value_from_list(body.filter.equals, "point_id")

    if not point_id or point_id <= 0:
        log.warning("param exception, equals is NULL, no point_id")
        raise ParamException(
            message="param exception, equals is NULL, no point_id")
    # 3. 获取常规参数统计和电能质量统计
    # 获取时间
    try:
        date_start = body.filter.ranges[0].start
        date_end = body.filter.ranges[0].end
    except:
        log.error("param error, ranges is NULL")
        raise ParamException(message="param error, ranges is NULL")
    # return await elec_index_service(cid, point_id, date_start, date_end)
    return await elec_index_service_new15(cid, point_id, date_start, date_end)


@summary("电能质量-历史曲线")
@description("包含电压偏差、频率偏差、三相不平衡、谐波畸变率曲线")
@examples(qual_history__example)
async def post_qual_history(req, body: PageRequest) -> QualHistoryResponse:
    #  1.获取intervel和时间轴
    try:
        date_start = body.filter.ranges[0].start
        date_end = body.filter.ranges[0].end
    except:
        log.error("param error, ranges is NULL")
        raise ParamException(message="param error, ranges is NULL")

    try:
        intervel, slots = time_format.time_pick_transf(date_start, date_end)
    except:
        log.error("param error, date format error")
        raise ParamException(message="param error, date format error")

    point_id = filed_value_from_list(body.filter.equals, "point_id")

    if not point_id or point_id <= 0:
        log.warning("param exception, equals is NULL, no point_id")
        raise ParamException(
            message="param exception, equals is NULL, no point_id")
    # return await qual_history_service(date_start, date_end, intervel, slots,
    #                                   point_id)
    return await qual_history_service_new15(date_start, date_end, intervel,
                                            slots, point_id)


async def qual_history_service(date_start, date_end, intervel, slots, point_id):
    # 2.获取曲线数据
    # 2.1 起始时间分别转化为时间戳
    es_start_dt = str(
        my_pendulum.from_format(date_start, "YYYY-MM-DD HH:mm:ss"))
    es_end_dt = str(my_pendulum.from_format(date_end, "YYYY-MM-DD HH:mm:ss"))
    range = Range(field="quarter_time", start=es_start_dt, end=es_end_dt)
    equal = Equal(field="pid", value=point_id)
    filter = Filter(equals=[equal], ranges=[range], in_groups=[], keywords=[])
    page_request = PageRequest(page_size=1, page_num=1, sort=None,
                               filter=filter)

    ctnum, _ = await get_wiring_type(point_id)
    if ctnum not in [2, 3]:
        log.error(
            f"qual_history point_id={point_id}　ctnum={ctnum} 无法获取到ctnum 装置已经被拆")
        ctnum = 3

    if ctnum == 2:
        stats_items = [
            "fdia_mean",  # 用于计算电流谐波有效值
            "fdic_mean",
            "uab_dev_mean",
            "ucb_dev_mean",
            "freq_dev_mean",
            "ubl_mean",
            "ibl_mean",
            "thduab_mean",
            "thducb_mean",
            "thdia_mean",
            "thdic_mean",
            "hr3ia_mean",
            "hr5ia_mean",
            "hr7ia_mean",
            "hr9ia_mean",
            "hr11ia_mean",
            "hr13ia_mean",
            "hr3ic_mean",
            "hr5ic_mean",
            "hr7ic_mean",
            "hr9ic_mean",
            "hr11ic_mean",
            "hr13ic_mean",
            "hr3uab_mean",
            "hr5uab_mean",
            "hr7uab_mean",
            "hr9uab_mean",
            "hr11uab_mean",
            "hr13uab_mean",
            "hr3ucb_mean",
            "hr5ucb_mean",
            "hr7ucb_mean",
            "hr9ucb_mean",
            "hr11ucb_mean",
            "hr13ucb_mean",
        ]
    else:
        stats_items = [
            "fdia_mean",  # 用于计算电流谐波有效值
            "fdib_mean",
            "fdic_mean",
            "ua_dev_mean",
            "ub_dev_mean",
            "uc_dev_mean",
            "freq_dev_mean",
            "ubl_mean",
            "ibl_mean",
            "thdua_mean",
            "thdub_mean",
            "thduc_mean",
            "thdia_mean",
            "thdib_mean",
            "thdic_mean",
            "hr3ia_mean",
            "hr5ia_mean",
            "hr7ia_mean",
            "hr9ia_mean",
            "hr11ia_mean",
            "hr13ia_mean",
            "hr3ib_mean",
            "hr5ib_mean",
            "hr7ib_mean",
            "hr9ib_mean",
            "hr11ib_mean",
            "hr13ib_mean",
            "hr3ic_mean",
            "hr5ic_mean",
            "hr7ic_mean",
            "hr9ic_mean",
            "hr11ic_mean",
            "hr13ic_mean",
            "hr3ua_mean",
            "hr5ua_mean",
            "hr7ua_mean",
            "hr9ua_mean",
            "hr11ua_mean",
            "hr13ua_mean",
            "hr3ub_mean",
            "hr5ub_mean",
            "hr7ub_mean",
            "hr9ub_mean",
            "hr11ub_mean",
            "hr13ub_mean",
            "hr3uc_mean",
            "hr5uc_mean",
            "hr7uc_mean",
            "hr9uc_mean",
            "hr11uc_mean",
            "hr13uc_mean",
        ]
    query_body = EsQuery.aggr_history_new(
        page_request, interval=intervel, stats_items=stats_items,
        histogram_field="quarter_time"
    )

    async with EsUtil() as es:
        es_results = await es.search_origin(body=query_body,
                                            index=constants.POINT_15MIN_INDEX)

    aggs_res = es_results.get("aggregations", {})
    data_buckets = aggs_res.get("aggs_name", {}).get("buckets", [])
    time_bucket_map = {i["key_as_string"]: i for i in data_buckets}
    log.info(
        f"post_qual_history query_body={query_body}, slots={slots} time_bucket_map.keys={list(time_bucket_map.keys())}"
    )
    elec_data = {stats_item: [] for stats_item in stats_items}
    for slot in slots:
        if slot in time_bucket_map:
            for stats_item in stats_items:
                value = time_bucket_map[slot].get(stats_item, {}).get("avg",
                                                                      "")
                # TODO：电压偏差和频率偏差暂时采用手段计算方式，后期直接读ES数据
                if value and stats_item == "freq_dev_mean":
                    # 如果频率偏差保留两位小数之后为0了，那么直接返回0,防止出现-0.00 的情况
                    if abs(value) < 0.005:
                        value = 0
                elec_data[stats_item].append(value)
        else:
            for stats_item in stats_items:
                elec_data[stats_item].append("")
    voltage_dev = VoltageDev(
        **{
            k.rsplit("_", 1)[0]: v
            for k, v in elec_data.items()
            if
            k.rsplit("_", 1)[0] in [field.name for field in fields(VoltageDev)]
        }
    )
    three_phase_unbalance = ThreePhaseImbalance(
        voltage=elec_data["ubl_mean"], current=elec_data["ibl_mean"]
    )
    voltage_harmonic = VoltageHarmonic(
        **{
            k.rsplit("_", 1)[0]: v
            for k, v in elec_data.items()
            if k.rsplit("_", 1)[0] in [field.name for field in
                                       fields(VoltageHarmonic)]
        }
    )
    # 新增电流谐波有效值 = 电流*畸变率 前端处理
    current_harmonic = CurrentHarmonic(
        **{
            k.rsplit("_", 1)[0]: v
            for k, v in elec_data.items()
            if k.rsplit("_", 1)[0] in [field.name for field in
                                       fields(CurrentHarmonic)]
        }
    )
    # 识电U只有一项有数据,返回具体的项
    sdu_i = None
    sdu_u = None
    if ctnum == 2:
        if any(elec_data["uab_dev_mean"]) and not any(
                elec_data["ucb_dev_mean"]):
            sdu_i = "ia"
            sdu_u = "uab"
        if any(elec_data["ucb_dev_mean"]) and not any(
                elec_data["uab_dev_mean"]):
            sdu_i = "ic"
            sdu_u = "ucb"
    else:
        if (
                any(elec_data["ua_dev_mean"])
                and not any(elec_data["ub_dev_mean"])
                and not any(elec_data["uc_dev_mean"])
        ):
            sdu_i = "ia"
            sdu_u = "ua"
        if (
                any(elec_data["ub_dev_mean"])
                and not any(elec_data["ua_dev_mean"])
                and not any(elec_data["uc_dev_mean"])
        ):
            sdu_i = "ib"
            sdu_u = "ub"
        if (
                any(elec_data["uc_dev_mean"])
                and not any(elec_data["ua_dev_mean"])
                and not any(elec_data["ub_dev_mean"])
        ):
            sdu_i = "ic"
            sdu_u = "uc"

    return QualHistoryResponse(
        ctnum=ctnum,
        voltage_dev=voltage_dev,
        freq_dev=elec_data["freq_dev_mean"],
        three_phase_unbalance=three_phase_unbalance,
        voltage_harmonic=voltage_harmonic,
        current_harmonic=current_harmonic,
        time_slots=slots,
        sdu_i=sdu_i,
        sdu_u=sdu_u,
    )


async def qual_history_service_new15(start, end, intervel, slots, pid):
    ctnum = await get_wiring_type_new15(pid)
    if intervel == 900:
        table_name = "point_15min_electric"
        date_format = "%%H:%%i"
    else:
        table_name = "point_1day_electric"
        date_format = "%%m-%%d"
    datas = await get_qual_history_dao(table_name, pid, start, end, date_format)
    datas = {data["date_time"]: data for data in datas}
    if ctnum == 2:
        # 用于计算电流谐波有效值
        stats_items = [
            "fdia_mean", "fdic_mean", "uab_dev_mean", "ucb_dev_mean",
            "freq_dev_mean", "ubl_mean", "ibl_mean", "thduab_mean",
            "thducb_mean", "thdia_mean", "thdic_mean", "hr3ia_mean",
            "hr5ia_mean", "hr7ia_mean", "hr9ia_mean", "hr11ia_mean",
            "hr13ia_mean", "hr3ic_mean", "hr5ic_mean", "hr7ic_mean",
            "hr9ic_mean", "hr11ic_mean", "hr13ic_mean", "hr3uab_mean",
            "hr5uab_mean", "hr7uab_mean", "hr9uab_mean", "hr11uab_mean",
            "hr13uab_mean", "hr3ucb_mean", "hr5ucb_mean", "hr7ucb_mean",
            "hr9ucb_mean", "hr11ucb_mean", "hr13ucb_mean",
        ]
    else:
        ctnum = 3
        # 用于计算电流谐波有效值
        stats_items = [
            "fdia_mean",  "fdib_mean", "fdic_mean", "ua_dev_mean",
            "ub_dev_mean", "uc_dev_mean", "freq_dev_mean", "ubl_mean",
            "ibl_mean", "thdua_mean", "thdub_mean", "thduc_mean", "thdia_mean",
            "thdib_mean", "thdic_mean", "hr3ia_mean", "hr5ia_mean",
            "hr7ia_mean", "hr9ia_mean", "hr11ia_mean", "hr13ia_mean",
            "hr3ib_mean", "hr5ib_mean", "hr7ib_mean", "hr9ib_mean",
            "hr11ib_mean", "hr13ib_mean", "hr3ic_mean", "hr5ic_mean",
            "hr7ic_mean", "hr9ic_mean", "hr11ic_mean", "hr13ic_mean",
            "hr3ua_mean", "hr5ua_mean", "hr7ua_mean", "hr9ua_mean",
            "hr11ua_mean", "hr13ua_mean", "hr3ub_mean", "hr5ub_mean",
            "hr7ub_mean", "hr9ub_mean", "hr11ub_mean", "hr13ub_mean",
            "hr3uc_mean", "hr5uc_mean", "hr7uc_mean", "hr9uc_mean",
            "hr11uc_mean", "hr13uc_mean"
        ]
    elec_data = {stats_item: [] for stats_item in stats_items}
    for slot in slots:
        if slot in datas.keys():
            for stats_item in stats_items:
                value = datas[slot].get(stats_item, "")
                if value and stats_item == "freq_dev_mean":
                    # 如果频率偏差保留两位小数之后为0了，那么直接返回0,防止出现-0.00 的情况
                    if abs(value) < 0.05:
                        value = 0
                elec_data[stats_item].append(value)
        else:
            for stats_item in stats_items:
                elec_data[stats_item].append("")

    voltage_dev = VoltageDev(
        **{
            k.rsplit("_", 1)[0]: v
            for k, v in elec_data.items()
            if
            k.rsplit("_", 1)[0] in [field.name for field in fields(VoltageDev)]
        }
    )
    three_phase_unbalance = ThreePhaseImbalance(
        voltage=elec_data["ubl_mean"], current=elec_data["ibl_mean"]
    )
    voltage_harmonic = VoltageHarmonic(
        **{
            k.rsplit("_", 1)[0]: v
            for k, v in elec_data.items()
            if k.rsplit("_", 1)[0] in [field.name for field in
                                       fields(VoltageHarmonic)]
        }
    )
    # 新增电流谐波有效值 = 电流*畸变率 前端处理
    current_harmonic = CurrentHarmonic(
        **{
            k.rsplit("_", 1)[0]: v
            for k, v in elec_data.items()
            if k.rsplit("_", 1)[0] in [field.name for field in
                                       fields(CurrentHarmonic)]
        }
    )
    # 识电U只有一项有数据,返回具体的项
    sdu_i = None
    sdu_u = None
    if ctnum == 2:
        if any(elec_data["uab_dev_mean"]) and not any(
                elec_data["ucb_dev_mean"]):
            sdu_i = "ia"
            sdu_u = "uab"
        if any(elec_data["ucb_dev_mean"]) and not any(
                elec_data["uab_dev_mean"]):
            sdu_i = "ic"
            sdu_u = "ucb"
    else:
        if (
                any(elec_data["ua_dev_mean"])
                and not any(elec_data["ub_dev_mean"])
                and not any(elec_data["uc_dev_mean"])
        ):
            sdu_i = "ia"
            sdu_u = "ua"
        if (
                any(elec_data["ub_dev_mean"])
                and not any(elec_data["ua_dev_mean"])
                and not any(elec_data["uc_dev_mean"])
        ):
            sdu_i = "ib"
            sdu_u = "ub"
        if (
                any(elec_data["uc_dev_mean"])
                and not any(elec_data["ua_dev_mean"])
                and not any(elec_data["ub_dev_mean"])
        ):
            sdu_i = "ic"
            sdu_u = "uc"

    return QualHistoryResponse(
        ctnum=ctnum,
        voltage_dev=voltage_dev,
        freq_dev=elec_data["freq_dev_mean"],
        three_phase_unbalance=three_phase_unbalance,
        voltage_harmonic=voltage_harmonic,
        current_harmonic=current_harmonic,
        time_slots=slots,
        sdu_i=sdu_i,
        sdu_u=sdu_u,
    )


@summary("电能质量-实时参数")
@description("包含用电健康指数、电压偏差、频率偏差、三相不平衡度、谐波畸变率")
@examples(qual_current_example)
async def post_qual_current(req, body: PageRequest) -> QualCurrentResponse:
    try:
        point_id = filed_value_from_list(body.filter.equals, "point_id")
        cid = req.json["cid"]
    except:
        log.warning("param exception, equals is NULL, no point_id")
        raise ParamException(
            message="param exception, equals is NULL, no point_id")

    if point_id <= 0 or not point_id or cid <= 0:
        log.warning("param exception, equals is NULL, no point_id")
        raise ParamException(
            message="param exception, equals is NULL, no point_id")
    #  获取mtid
    meter_info = await get_meter_by_point_new15(point_id)
    if not meter_info:
        raise BusinessException(
            message="没有该监测点的monitor信息,请联系运维人员!")
    mtid = meter_info["mtid"]
    # 获取子表中的实时数据
    url = f"{SETTING.stb_url}db_electric?tz=Asia/Shanghai"
    sql = f"select last_row(*) from mt{mtid}_ele where pid={point_id}"
    is_succ, results = await get_td_engine_data(url, sql)
    log.info(f"is_succ:{is_succ}")
    if is_succ:
        head = [re.findall(r'last_row\((.*)\)', i)[0] if "(" in i else i
                for i in results["head"]]
        if not results["data"]:
            results["data"] = ['' for i in range(len(head))]
        res = dict(zip(head, results["data"][0]))
        ctnum = res.get("ctnum") or 3
        harmonic = json.loads(res.get("harmonic")) if res.get("harmonic") else {}
        voltage_harmonic_dict, current_harmonic_dict = {}, {}
        for k in [field.name for field in fields(VoltageHarmonicRate)]:
            if k in harmonic.keys():
                voltage_harmonic_dict[k] = harmonic.get(k) or ''
            else:
                voltage_harmonic_dict[k] = ''
        voltage_harmonic = VoltageHarmonicRate(**voltage_harmonic_dict)
        for k in [field.name for field in fields(CurrentHarmonicRate)]:
            if k in harmonic.keys():
                current_harmonic_dict[k] = harmonic.get(k) or ''
            else:
                current_harmonic_dict[k] = ''
        current_harmonic = CurrentHarmonicRate(**current_harmonic_dict)
        health_index = await health_score.load_health_index(cid, point_id)
        ret_items = [
            "ua_dev",
            "ub_dev",
            "uc_dev",
            "uab_dev",
            "ucb_dev",
            "freq_dev",
            "ubl",
            "ibl",
            "sdu_i",
            "sdu_u",
        ]

        # 识电U只有一项有数据,返回具体的项
        res = get_sdu_i_and_u(res, ctnum)
        if res.get("ts"):
            time_str = str(res["ts"])[0:-4]
        else:
            time_str = time_format.get_datetime_str(0)
        return QualCurrentResponse(
            ctnum=ctnum,
            real_time=time_str,
            health_index=health_index,
            voltage_harmonic=voltage_harmonic,
            current_harmonic=current_harmonic,
            **{k: v for k, v in res.items() if k in ret_items},
        )
    else:
        raise BusinessException(message="数据查询失败!")


@summary("用电监测-实时监测-楼层")
async def post_elec_current_storeys(req, body: EcsReq) -> EscResp:
    storeys = body.storeys
    return await elec_current_storeys_service(storeys)


@summary("电能质量-实时参数-楼层")
async def post_qual_current_storeys(req, body: EcsReq) -> QcsResp:
    storeys = body.storeys
    return await qual_current_storeys_service(storeys)


@summary("用电监测-卡片信息-level")
async def post_elec_card_level(req, body: CidPointsReq) -> EclResp:
    point_list = body.point_list
    return await elec_card_level_service(point_list)


@summary("电能质量-卡片信息-level")
async def post_qual_current_level(req, body: CidPointsReq) -> QclResp:
    point_list = body.point_list
    return await qual_current_level_service(point_list)
