# -*- coding:utf-8 -*-
from collections import defaultdict
from datetime import datetime

from pot_libs.logger import log
from pot_libs.mysql_util.mysql_util import MysqlUtil
from unify_api.modules.common.procedures.points import point_to_mid
from unify_api.modules.common.dao.common_dao import (
    load_user_lang, load_monitor_names
)


async def get_company(company_id):
    raw_sql = "select cid from company where cid = %s"
    async with MysqlUtil() as conn:
        company = await conn.fetchone(sql=raw_sql, args=(company_id,))
    return company


async def company_available(company_id):
    company = await get_company(company_id)
    if company:
        return True
    return False


def check_value_is_null(value):
    return value in (None, "null", "NULL", "")


async def get_user_hardware_info(cid, page_num, page_size):
    # 1. 获取总的point数量
    async with MysqlUtil() as conn:
        point_sql_tmp = "select p.pid, p.name, p.create_time, p.update_time " \
                        "from monitor c " \
                        "left join point p on p.mtid = c.mtid " \
                        "left join monitor_reuse m on m.mtid  = c.mtid " \
                        "where c.demolished=0 " \
                        "and (p.cid =%s or m.cid = %s) "
        points_tmp = await conn.fetchall(point_sql_tmp, (cid, cid))
    point_ids_tmp = [point["pid"] for point in points_tmp]
    # 拆表
    point_mid_map_tmp, point_count = await point_to_mid(point_ids_tmp)
    point_id_tmp = point_mid_map_tmp.keys()
    # 2. 获取分页
    offset = (page_num - 1) * page_size
    async with MysqlUtil() as conn:
        point_sql = "select pid, name, create_time, update_time, position " \
                    "from point where cid = %s or pid in %s " \
                    "limit %s offset %s"
        points = await conn.fetchall(sql=point_sql, args=(
            cid, tuple(point_id_tmp), page_size, offset))
    point_ids = [point["pid"] for point in points]
    # 获取所有poin_id和mid对应关系
    point_mid_map, point_count_limit = await point_to_mid(point_ids)
    # 去调拆表的POINT
    points = [point for point in points if point["pid"] in point_mid_map]

    meter_change_sql = (
        "select pid, mtid from `point` where pid in %s order by pid, create_time"
    )
    meter_changes = []
    if point_ids:
        async with MysqlUtil() as conn:
            meter_changes = await conn.fetchall(meter_change_sql,
                                                args=(tuple(point_ids),))
    point_meter_map = defaultdict(dict)
    for i in meter_changes:
        point_meter_map[i["pid"]] = i

    meter_ids = [i["mtid"] for i in point_meter_map.values()]
    meters, meter_param_records = [], []
    if meter_ids:
        async with MysqlUtil() as conn:
            meter_sql = "select mtid, sid from `monitor` where mtid in %s"
            meters = await conn.fetchall(meter_sql, args=(tuple(meter_ids),))

        async with MysqlUtil() as conn:
            meter_param_record_sql = """SELECT
                    mtid,
                    ptr,
                    ctr,
                    ctnum,
                    voltage_side,
                    vc,
                    tc 
                FROM
                    `point` 
                WHERE
                    mtid IN % s 
                ORDER BY
                    mtid,
                    create_time"""
            meter_param_records = await conn.fetchall(
                meter_param_record_sql, args=(tuple(meter_ids),)
            )

    meter_map = {m["mtid"]: m for m in meters}
    meterparam_map = {m["mtid"]: m for m in meter_param_records}

    log.info("meter_ids = {}".format(meter_ids))
    log.info("meter_map = {}".format(meter_map))
    log.info("meterparam_map = {}".format(meterparam_map))
    # 组装point_id和meter_param的对应关系
    point_meterparam_map = defaultdict(dict)
    for point_id, meter_change in point_meter_map.items():
        if meter_change["mtid"] not in meterparam_map:
            log.warn(f"mtid={meter_change['mtid']}沒有meter_param_records")
            continue
        point_meterparam_map[point_id] = meterparam_map[meter_change["mtid"]]

    # 组装pid和meter的对应关系
    for point_id, meter_change in point_meter_map.items():
        point_meter_map[point_id] = meter_map[meter_change["mtid"]] if \
            meter_change["mtid"] else {}

    datas = []
    for point in points:
        data = {}
        for k in [
            "installed_location",
            "device_number",
            "device_type",
            "start_time",
            "update_time",
            "ct_change",
            "pt_change",
            "wiring_type",
            "inline_capacity",
            "high_or_low_side",
            "rated_voltage",
            "belong_number",
            "position",
        ]:
            data[k] = ""
        data["installed_location"] = point["name"]
        data["position"] = point["position"]
        if point.get("create_time"):
            data["start_time"] = datetime.strftime(
                datetime.fromtimestamp(point["create_time"]), "%Y-%m-%d %H:%M"
            )
        if point.get("update_time"):
            data["update_time"] = datetime.strftime(
                datetime.fromtimestamp(point["update_time"]), "%Y-%m-%d %H:%M"
            )

        point_id = point["pid"]
        meter = point_meter_map.get(point_id)
        if meter:
            data["device_number"] = meter["sid"]
        meter_param = point_meterparam_map.get(point_id)
        if meter_param:
            data["pt_change"] = meter_param["ptr"]
            data["ct_change"] = meter_param["ctr"]
            data["wiring_type"] = "两表法" if meter_param["ctnum"] == 2 else "三表法"
            if not check_value_is_null(meter_param["voltage_side"]):
                data["high_or_low_side"] = "高压侧" if meter_param[
                                                        "voltage_side"] == 1 else "低压侧"
            if not check_value_is_null(meter_param["tc"]):
                data["inline_capacity"] = meter_param["tc"]
            if not check_value_is_null(meter_param["vc"]):
                data["rated_voltage"] = meter_param["vc"]

        datas.append(data)
    return {
        "rows": datas,
        "total": point_count,
    }


async def load_hardware_info(cid, pg, pg_size, user_id):
    sql = "SELECT p.*, m.sid, m.mtid FROM `point` p left join monitor m " \
          "on p.mtid=m.mtid where m.demolished=0 and p.cid=%s  " \
          "ORDER BY p.create_time desc"
    async with MysqlUtil() as conn:
        datas = await conn.fetchall(sql=sql, args=(cid,))
    results = []
    if pg > 0 and pg_size > 0:
        start = (pg - 1) * pg_size
        end = pg * pg_size
    else:
        start, end = 0, 10

    lang = await load_user_lang(user_id)
    if lang != "zh_CN":
        mtids = [r["mtid"] for r in datas]
        mtr_names = await load_monitor_names(mtids, lang)
    else:
        mtr_names = {}

    for data in datas:
        mtid = data["mtid"]
        high_or_low_side = "高压侧" if data["voltage_side"] == 1 else "低压侧"
        start_time = datetime.strftime(
            datetime.fromtimestamp(data["create_time"]), "%Y-%m-%d %H:%M"
        )
        update_time = datetime.strftime(
            datetime.fromtimestamp(data["update_time"]), "%Y-%m-%d %H:%M"
        )
        wiring_type = "两表法" if data["ctnum"] == 2 else "三表法"
        name = data.get("name") or ''
        mtr_name = name if lang == "zh_CN" else mtr_names.get(mtid, name)
        results.append({
            "installed_location": mtr_name,
            "device_number": data.get("sid") or '',
            "device_type": data.get("device_type") or '',
            "start_time": start_time,
            "update_time": update_time,
            "ct_change": data.get("ctr") or '',
            "pt_change": data.get("ptr") or '',
            "wiring_type": wiring_type,
            "inline_capacity": data.get("tc") or '',
            "high_or_low_side": high_or_low_side,
            "rated_voltage": data.get("vc") or '',
            "belong_number": data.get("belong_number") or '',
            "position": data.get("position") or '',
        })
    return {
        "rows": results[start: end],
        "total": len(results),
    }


async def hardware_statistics(company_id):
    """
    获取硬件信息总统计
    :param company_id:
    :return:
    """
    async with MysqlUtil() as conn:
        sql = "select p.pid from point p " \
              "left JOIN monitor c on p.mtid = c.mtid " \
              "left join monitor_reuse m on c.mtid = m.mtid " \
              "where c.demolished=0 and " \
              "(p.cid =%s or m.cid=%s)"
        points = await conn.fetchall(sql, (company_id, company_id))
    point_ids = [point["pid"] for point in points]
    mid_info, point_count = await point_to_mid(point_ids)

    async with MysqlUtil() as conn:
        inline_sql = "select count(*) as inline_count from inline where " \
                     "cid = %s"
        inline_count_map = await conn.fetchone(inline_sql, (company_id,))
    inline_count = inline_count_map["inline_count"]

    async with MysqlUtil() as conn:
        time_sql = "select create_time from company where cid = %s"
        create_time_map = await conn.fetchone(sql=time_sql, args=(company_id,))

    create_time_timestamp = create_time_map["create_time"]
    start_time = datetime.strftime(
        datetime.fromtimestamp(create_time_timestamp), "%Y-%m-%d %H:%M")
    # power_capacity供电容量字段计算错误，改为inline表的tc_runtime字段相加
    async with MysqlUtil() as conn:
        capacity_sql = "select tc_runtime from inline where cid = %s"
        capacity_list = await conn.fetchall(capacity_sql, (company_id,))
    power_capacity = 0
    for capacity in capacity_list:
        if capacity and capacity.get("tc_runtime"):
            power_capacity += capacity["tc_runtime"]
    return {
        "installed_number": point_count,
        "legal_measurement_number": inline_count,
        "start_time": start_time,
        "power_capacity": power_capacity if power_capacity else "",
    }
