from collections import defaultdict

from pot_libs.mysql_util.mysql_util import MysqlUtil
from unify_api.modules.common.components.list_points_cps import CommonLocation, \
    CommonPoint, Inline, ListPointResponse
from unify_api.modules.common.dao.common_dao import query_points_by_storey


async def get_points(company_ids):
    """
    获取一个工厂的有效监测点
    :param company_id:
    :return: 返回{"cid": {"point_id": point_info}}
    """
    company_point_map = defaultdict(dict)
    async with MysqlUtil() as conn:
        point_sql = (
            "select pid, cid cid, inlid from point where cid in %s"
        )
        points = await conn.fetchall(point_sql, args=(company_ids,))
        company_point_ids_map = defaultdict(list)
        for point in points:
            company_point_ids_map[point["cid"]].append(point["pid"])

        point_map = {i["pid"]: i for i in points}
        point_ids = list(point_map.keys())
        pid_field, start_time_field = "pid", "start_time"
        sql = f"SELECT pid, mid FROM change_meter_record WHERE pid in %s ORDER BY {pid_field}, {start_time_field}"
        records = await conn.fetchall(sql, args=(point_ids,))

        newest_point_meter_relation = {i["pid"]: i["mid"] for i in records if
                                       i["mid"]}
        valid_mids = list(newest_point_meter_relation.values())
        newest_record_map = {i["pid"]: point_map.get(i["pid"]) for i in records
                             if i["mid"]}

    # 根据有效的meter id查询meter参数
    async with MysqlUtil() as conn:
        mid_field, start_time_field = "mid", "start_time"
        mp_sql = f"SELECT vc, mid, ctnum FROM meter_param_record WHERE mid in %s ORDER BY {mid_field}, {start_time_field}"
        mps = await conn.fetchall(mp_sql, args=(valid_mids,))
        meter_param_map = {i["mid"]: i for i in mps}

    for cid, point_ids in company_point_ids_map.items():
        for point_id in point_ids:
            if point_id in newest_record_map:
                mid = newest_point_meter_relation[point_id]
                meter_param = meter_param_map.get(mid)
                if not meter_param:
                    # 如果不存在参数，拆了?
                    continue
                point_info = newest_record_map[point_id]
                point_info["meter_param"] = meter_param
                company_point_map[cid][point_id] = point_info
    return company_point_map


async def get_points_new15(cids):
    sql = "SELECT p.pid,p.cid,p.inlid,vc,ctnum " \
          "FROM `point` p INNER JOIN " \
          "monitor m on m.mtid=p.mtid where p.cid in %s and m.demolished=0;"
    async with MysqlUtil() as conn:
        points = await conn.fetchall(sql, args=(cids,))
    company_point_map = defaultdict(dict)
    for point in points:
        company_point_map[point["cid"]][point["pid"]] = point
    return company_point_map


async def get_points_num(cid):
    sql = "SELECT count(1) doc_count FROM `point` p LEFT JOIN monitor m " \
          "on m.mtid=p.mtid where m.demolished=0 and m.cid=%s"
    async with MysqlUtil() as conn:
        datas = await conn.fetchone(sql, args=(cid,))
    return datas["doc_count"]


async def proxy_points(cid_list):
    """获取代理下的所有监测点"""
    sql = "SELECT COUNT(p.pid) from point p LEFT JOIN monitor m " \
          "on p.mtid=m.mtid where p.cid in %s and m.demolished=0"
    async with MysqlUtil() as conn:
        num = await conn.fetch_value(sql, args=(tuple(cid_list),))
    return num


async def get_meter_by_point(point_id):
    """
        根据point获取设备数据
    """
    async with MysqlUtil() as conn:
        sql = "SELECT sid, meter_no,m.mtid FROM `point` p LEFT JOIN monitor " \
              "m on m.mtid=p.mtid where m.demolished=0 and p.pid=%s"
        meter_info = await conn.fetchone(sql, args=(point_id,))
        return meter_info


async def list_point(cid):
    list_point = []
    points = {}
    groups = {}
    sql = "SELECT pid, name, add_to_company FROM point WHERE cid=%s"
    async with MysqlUtil() as conn:
        result = await conn.fetchall(sql, args=(cid,))
        for res in result:
            pid = res.get("pid")
            points[pid] = res

    sql = "SELECT id, `group`, item FROM location WHERE cid=%s and `type` in %s"
    async with MysqlUtil() as conn:
        result = await conn.fetchall(sql, args=(
            cid, ["temperature", "residual_current"]))
        for res in result:
            id = res.get("id")
            group = res.get("group")
            item = res.get("item")
            groups.setdefault(group, []).append((id, item))

    for pid, point_info in points.items():
        name = point_info.get("name")
        add_to_company = point_info["add_to_company"]
        items = groups.get(name, [])
        locations = []
        for id, item in items:
            # comm_location = CommonLocation(location_id=id, item=item)
            comm_location = {"location_id": id, "item": item}
            locations.append(comm_location)
        # comm_point = CommonPoint(name=name, point_id=pid, locations=locations, add_to_company=add_to_company)
        comm_point = {"name": name, "point_id": pid, "locations": locations,
                      "add_to_company": add_to_company}
        list_point.append(comm_point)

    async with MysqlUtil() as conn:
        sql = "SELECT inlid, `name` FROM inline WHERE cid=%s"
        inlines = await conn.fetchall(sql, args=(cid,))
        inline_list = [Inline(inline_id=inline["inlid"], name=inline["name"])
                       for inline in inlines]
    return {"points": list_point, "inlines": inline_list}


async def point_to_mid(points):
    """获取所有poin_id和mid对应关系"""
    sql = "SELECT pid, mtid FROM point WHERE pid IN %s " \
          "order by pid, create_time"
    async with MysqlUtil() as conn:
        change_meter_records = await conn.fetchall(sql, args=(tuple(points),))
    point_mid_map = {
        i["pid"]: i["mtid"] for i in change_meter_records
    }
    point_mid = dict(filter(lambda x: x[1] is not None, point_mid_map.items()))
    return point_mid, len(point_mid)


async def points_by_storeys(storeys):
    """根据storey_id查询point_id和room_name"""
    point_list = await query_points_by_storey(storeys)
    return point_list
