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


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(company_id, 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 point p inner JOIN monitor c " \
                        "on p.mtid = c.mtid where p.cid=%s and c.demolished=0"
        points_tmp = await conn.fetchall(sql=point_sql_tmp, args=(company_id,))
    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 and pid in %s " \
                    "limit %s offset %s"
        points = await conn.fetchall(sql=point_sql, args=(company_id, 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, mid from `change_meter_record` where pid in %s order by pid, start_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["mid"] for i in point_meter_map.values()]
    meters, meter_param_records = [], []
    if meter_ids:
        async with MysqlUtil() as conn:
            meter_sql = "select mid, sid from `meter` where mid in %s"
            meters = await conn.fetchall(meter_sql, args=(tuple(meter_ids),))

        async with MysqlUtil() as conn:
            meter_param_record_sql = "select mid, ptr, ctr, ctnum, voltage_side, vc, tc, bureau_number, td_type from `meter_param_record` where mid in %s order by mid, start_time"
            meter_param_records = await conn.fetchall(
                meter_param_record_sql, args=(tuple(meter_ids),)
            )

    meter_map = {m["mid"]: m for m in meters}
    meterparam_map = {m["mid"]: 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["mid"] not in meterparam_map:
            log.warn(f"mid={meter_change['mid']}沒有meter_param_records")
            continue
        point_meterparam_map[point_id] = meterparam_map[meter_change["mid"]]

    # 组装pid和meter的对应关系
    for point_id, meter_change in point_meter_map.items():
        point_meter_map[point_id] = meter_map[meter_change["mid"]] if meter_change["mid"] 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"]
            if not check_value_is_null(meter_param["bureau_number"]):
                data["belong_number"] = meter_param["bureau_number"]
            if not check_value_is_null(meter_param["td_type"]):
                data["device_type"] = meter_param["td_type"]

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


async def get_user_hardware_info_new15(company_id, page_num, page_size):
    sql = "SELECT p.*,m.sid 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=(company_id, ))
    results = []
    if page_num > 0 and page_size > 0:
        start = (page_num - 1) * page_size
        end = page_num * page_size
    else:
        start, end = 0, 10
    for data in datas:
        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 "三表法"
        results.append({
            "installed_location": data.get("name") or '',
            "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:
    #     point_sql = "select count(*) as point_count from point where cid_belongedto = %s"
    #     point_count_map = await conn.fetchone(sql=point_sql, args=(company_id,))
    #
    # point_count = point_count_map["point_count"]
    async with MysqlUtil() as conn:
        point_sql = "select p.pid from point p inner JOIN monitor c " \
                    "on p.mtid = c.mtid where p.cid =%s and " \
                    "c.demolished=0"
        points = await conn.fetchall(sql=point_sql, args=(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(sql=inline_sql, args=(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(sql=capacity_sql, args=(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 "",
    }


async def hardware_statistics_new15(cid):
    """
    获取硬件信息总统计
    """
    sql = "SELECT c.create_time, p.pid FROM `point` p left join monitor m " \
          "on p.mtid=m.mtid LEFT JOIN company c on c.cid =p.cid " \
          "where m.demolished=0 and p.cid=%s"
    async with MysqlUtil() as conn:
        datas = await conn.fetchall(sql=sql, args=(cid,))
    if not datas:
        point_count, inline_count = 0, 0
        start_time, power_capacity = "", ""
    else:
        point_count = len(datas)
        create_time = datas[0]["create_time"]
        start_time = datetime.strftime(datetime.fromtimestamp(create_time),
                                       "%Y-%m-%d %H:%M")
        inline_sql = "select tc_runtime from inline where cid = %s"
        async with MysqlUtil() as conn:
            inline_dats = await conn.fetchall(sql=inline_sql, args=(cid,))
        inline_count = len(inline_dats)
        power_capacity = 0
        for inline_data in inline_dats:
            if inline_data.get("tc_runtime"):
                power_capacity += 1
    return {
        "installed_number": point_count,
        "legal_measurement_number": inline_count,
        "start_time": start_time,
        "power_capacity": power_capacity if power_capacity else "",
    }