import json
from quart import jsonify, request
from . import api
from web.common.utils import login_required
from core.DBManager import mDBM
from myutils.ReManager import mReM
from core.ModelManager import mMM
from myutils.ConfigManager import myCongif
import asyncio
import time

@api.route('/channel/tree',methods=['GET'])
@login_required
async def channel_tree(): #获取通道树
    strsql = ("select t2.area_name ,t1.ID ,t1.channel_name from channel t1 left join area t2 on t1.area_id = t2.id;")
    data = mDBM.do_select(strsql)
    channel_tree = [{"area_name": channel[0], "ID": channel[1],"channel_name":channel[2]} for channel in data]
    return jsonify(channel_tree)

@api.route('/channel/list',methods=['GET'])
async def channel_list(): #获取通道列表 --分页查询,支持区域和通道名称关键字查询
    strsql = ("select t2.area_name,t1.ID,t1.channel_name,t1.ulr,t1.'type',t1.status,t1.element_id,t4.model_name "
              "from channel t1 left join area t2 on t1.area_id = t2.id "
              "left JOIN channel2model t3 on t1.ID = t3.channel_id "
              "left JOIN model t4 on t3.model_id = t4.ID "
              "where t1.is_work=1 order by area_name desc;")
    data = mDBM.do_select(strsql)
    channel_list = [{"area_name": channel[0], "ID": channel[1], "channel_name": channel[2], "ulr": channel[3],
                     "type": channel[4], "status": channel[5],
                     "element_id": channel[6],"model_name":channel[7]} for channel in data]
    return jsonify(channel_list)

@api.route('/channel/info',methods=['GET'])
@login_required
async def channel_info(): #获取通道信息   ---- list已获取详情
    return jsonify(1)

@api.route('/channel/add',methods=['POST'])
@login_required
async def channel_add(): #新增通道 -- 2024-8-1修改为与修改通道用一个接口
    json_data = await request.get_json()
    area = json_data.get('area')
    cName = json_data.get('cName')
    Rtsp = json_data.get('Rtsp')
    cid = int(json_data.get('cid'))

    if mReM.is_valid_rtsp_url(Rtsp) is not True:
        reStatus = 0
        reMsg = 'rtsp地址不合法'
        return jsonify({'status': reStatus, 'msg': reMsg})
    strsql = f"select id from area where area_name = '{area}';"
    area = mDBM.do_select(strsql,1)
    if area:
        area_id = area[0]
        strsql = f"select ID from channel where area_id={area_id} and channel_name='{cName}';"
        data = mDBM.do_select(strsql, 1)
        if data and data[0] != cid: #有值--代表重复 或者是它自己(只修改了RTSP地址)
            reStatus = 0
            reMsg = "同一区域内的通道名称不能相同!"
        else:
            if cid == -1:
                max_count = myCongif.get_data("max_channel_num")
                strsql = "select count(*) from channel;"
                data = mDBM.do_select(strsql,1)
                if data[0] >= max_count:
                    reStatus = 0
                    reMsg = f"已达到最多通道数量-{max_count}通道,不能再添加"
                    return jsonify({'status': reStatus, 'msg': reMsg})
                strsql = (f"INSERT INTO channel (area_id,channel_name,ulr,'type',status) values "
                          f"({area_id},'{cName}','{Rtsp}',1,0);")
            else:
                strsql = (f"UPDATE channel SET area_id={area_id},channel_name='{cName}'"
                          f",ulr='{Rtsp}' where ID={cid};")
            ret = mDBM.do_sql(strsql)
            if ret == True:
                reStatus = 1
                if cid == -1:
                    reMsg = '添加通道成功'
                    #await asyncio.sleep(0.5)  # 休眠0.5,待数据更新完成
                    # 对新增的视频通道进行视频采集和
                    strsql = f"select ID from channel where area_id={area_id} and channel_name='{cName}';"
                    data = mDBM.do_select(strsql, 1)
                    if data:
                        cid = data[0]
                        mMM.start_work(cid)
                    else:
                        print(f"这里不应该没有值!!!!area_id-{area_id},cName--{cName}")
                        await asyncio.sleep(1)  #休眠一秒
                        strsql = f"select ID from channel where area_id={area_id} and channel_name='{cName}';"
                        data = mDBM.do_select(strsql, 1)
                        if data:
                            cid = data[0]
                            mMM.start_work(cid)
                        else:
                            print(f"这里真的不应该没有值了!!!!area_id-{area_id},cName--{cName}")

                elif cid >0: #cid 不会是0,以防万一
                    reMsg = '修改通道成功'
                    #需要先停再启动---不区分有没有修改URL了,就当有修改使用
                    mMM.stop_work(cid)
                    start_time = time.time()
                    mMM.start_work(cid)
                    end_time = time.time()
                    execution_time = end_time - start_time
                    print(f"开始一个通道线程,花费了: {execution_time} seconds")
            else:
                reStatus = 0
                if cid == -1:
                    reMsg = '添加通道失败,请联系技术支持!'
                else:
                    reMsg = '修改通道信息失败,请联系技术支持!'
    else:
        reStatus = 0
        reMsg = '错误的区域ID,请修改'
    return jsonify({'status':reStatus,'msg':reMsg})

@api.route('/channel/img',methods=['POST'])
@login_required
async def get_channel_img():
    '''获取一帧图片'''
    json_data = await request.get_json()
    cid = int(json_data.get('cid'))
    img_base64 = mMM.verify_list.cm_get_cap_frame(cid)
    if img_base64:
        # 返回JSON响应
        return jsonify({"image": img_base64})
    else:
        return jsonify({"error": "Failed to capture frame"}), 404

@api.route('/channel/del',methods=['POST'])
@login_required
async def channel_del(): #删除通道
    json_data = await request.get_json()
    cid = int(json_data.get('cid'))
    reStatus = 0
    if cid > 0:
        mMM.stop_work(cid)
        #删除该通道和算法的关联信息:布防时间,算法模型数据----使用外键级联删除会方便很多,只要一个删除就可以
        ret = mDBM.delchannel(cid)
        if ret == True:
            reStatus = 1
            reMsg = '删除通道信息成功'
        else:
            reMsg = '删除通道信息失败,请联系技术支持!'
    else:
        reMsg = '通道ID参数错误,请联系技术支持!'
    return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/check',methods=['GET'])
@login_required
async def channel_check(): #检查通道视频的在线情况--可以获取全部 ID-0,全部,1*具体通道ID--10分钟会更新一次在线状态-- 要验证
    ID = request.args.get('ID')
    if ID:
        ID = int(ID)
        if ID==0:
            strsql = "select ID,status from channel;"
        elif ID > 0:
            strsql = f"select ID,status from channel where ID={ID};"
        else:
            reStatus = 0
            reMsg = "参数错误"
            return jsonify({'status': reStatus, 'msg': reMsg})
        datas = mDBM.do_select(strsql)
        reStatus = 1
        reMsg = [{'ID': data[0], 'status': data[1]} for data in datas]
        return jsonify({'status': reStatus, 'msg': reMsg})
    else:
        reStatus = 0
        reMsg = "参数错误"
        return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/C2M',methods=['POST'])
@login_required
async def get_ctm_data():
    '''获取通道关联模型的相关数据'''
    json_data = await request.get_json()
    cid = int(json_data.get('cid'))
    #获取算法数据
    strsql = "select ID,model_name from model;"
    model_datas = mDBM.do_select(strsql)
    m_datas = []
    if model_datas:
        m_datas = [{'ID':row[0],'model_name':row[1]} for row in model_datas]
    #获取c2m数据
    strsql = f"select ID,model_id,check_area,polygon,conf_thres,iou_thres from channel2model where channel_id = {cid};"
    c2m_data = mDBM.do_select(strsql,1)
    #schedule数据
    schedule = []
    if c2m_data:
        c2m_data_json = [{'model_id':c2m_data[1],'check_area':c2m_data[2],'polygon':c2m_data[3],
                          'conf_thres':c2m_data[4],'iou_thres':c2m_data[5]}]
        c2m_id = c2m_data[0]
        strsql = f"select day,hour,status from schedule where channel2model_id ={c2m_id} order by hour asc,day asc;"
        schedule_datas = mDBM.do_select(strsql)
        if schedule_datas:
            schedule = [{'day': row[0], 'hour': row[1], 'status': row[2]} for row in schedule_datas]
        else:
            schedule = []
    else:
        schedule = []
        c2m_data_json = []
    #返回数据
    redata = {"m_datas":m_datas,"c2m_data":c2m_data_json,"schedule":schedule}
    return jsonify(redata)

@api.route('/channel/chanegeC2M',methods=['POST'])
@login_required
async def change_c_t_m():
    '''
    修改和新增与通道关联的算法模块
    :return:
    '''
    json_data = await request.get_json()
    model_name = json_data.get('model_name')
    check_area = json_data.get('check_area')
    polygon_str = json_data.get('polygon_str')
    iou_thres = json_data.get('iou_thres')
    conf_thres = json_data.get('conf_thres')
    schedule = json_data.get('schedule')
    cid = int(json_data.get('cid'))
    #返回数据
    reStatus = 0
    reMsg = "更新失败,请联系技术支持!"

    #开始更新--- 统一先停止原通道工作线程
    if model_name=="请选择":
        strsql = f"select ID from channel2model where channel_id={cid};"
        data = mDBM.do_select(strsql,1)
        if data:
            #需要删除数据
            ret = mDBM.delC2M(cid,1)  #只是删除了数据库数据
            if ret:
                #停止该通道的model线程
                mMM.restartC2M(cid) #没有模型关联数据,模型工作线程不会启动
                reStatus = 1
                reMsg = "更新成功"
        else:   #原本就没数据
            reStatus = 1
            reMsg = "更新成功"
    else: #新增关联或修改关联
        # 验证数据
        if conf_thres <= 0 or conf_thres >= 1 or iou_thres <= 0 or iou_thres >= 1:
            reMsg = "阈值的有效范围是大于0,小于1;请输入正确的阈值"
            return jsonify({'status': reStatus, 'msg': reMsg})
        c2m_id = updateModel(cid,model_name,check_area,polygon_str,conf_thres,iou_thres) #c2m表
        if c2m_id != 0:
            ret = updataSchedule(c2m_id,schedule.replace("'", "\""))   #schedule表
            if ret:
                # 重启下通道的工作线程
                print(f"restartC2M--{cid}")
                mMM.restartC2M(cid) #没有模型关联数据,模型工作线程不会启动
                reStatus = 1
                reMsg = "更新成功"
    return jsonify({'status': reStatus, 'msg': reMsg})


def updataSchedule(c2m_id,schedule):
    # schedule_data_str = ("{'6': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
    #                      "'0': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
    #                      "'1': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
    #                      "'2': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
    #                      "'3': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],"
    #                      "'4': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],"
    #                      "'5': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}")
    #先删
    strsql = f"delete from schedule where channel2model_id={c2m_id};"
    mDBM.do_sql(strsql)
    #再加
    json_object = json.loads(schedule)
    for day, hours in json_object.items():
        for hour, status in enumerate(hours):
            strsql = (
                f"insert into schedule (channel2model_id,day,hour,status) values ({c2m_id},'{day}',{hour},{status})"
                f" on conflict(channel2model_id,day,hour) do update set status=excluded.status;")
            ret = mDBM.do_sql(strsql)
            if not ret: #插入失败后,需要删除所有数据
                strsql = f"delete from schedule where channel2model_id={c2m_id};"
                mDBM.do_sql(strsql)
                return ret
    return 1

def updateModel(channel_id,model_name,check_area,polygon_str,conf_thres,iou_thres):
    '''新增和修改通道关联的模型 ----约束:一个通道只能关联一个算法模型
        return 0 失败, 其他为c2m_id
    '''
    reStatus = 0
    strsql = f"select ID from channel where ID={channel_id};"
    if mDBM.do_select(strsql, 1):  # 通道号在数据库中
        strsql = f"select ID from model where model_name = '{model_name}';"
        data = mDBM.do_select(strsql, 1)
        if data:    #通道和模型都有对应数据
            reStatus = mDBM.updateC2M(channel_id, data[0],check_area,polygon_str,conf_thres,iou_thres)
    return reStatus

@api.route('/channel/area/list',methods=['GET'])
@login_required
async def channel_area_list():
    '''获取所属区域list'''
    strsql = "select * from area;"
    datas = mDBM.do_select(strsql)
    reMsg = [{'id': data[0], 'area_name': data[1]} for data in datas]
    return jsonify(reMsg)

@api.route('/channel/area/change',methods=['POST'])
@login_required
async def channel_area_change(): #修改区域名称
    area_id = (await request.form)['id']
    area_name = (await request.form)['name']
    strsql = f"select id from area where area_name='{area_name}';"
    datas = mDBM.do_select(strsql)
    if datas:
        reStatus = 0
        reMsg = '区域名称重复,请修改!'
    else:
        strsql = f"update area set area_name='{area_name}' where id = {area_id};"
        ret = mDBM.do_sql(strsql)
        if ret == True:
            reStatus = 1
            reMsg = '修改通道名称成功'
        else:
            reStatus = 0
            reMsg = '修改通道名称失败,请联系技术支持!'
    return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/area/del',methods=['POST'])
@login_required
async def channel_area_del(): #删除区域
    area_id = (await request.form)['id']
    strsql = f"select * from channel where area_id={area_id};"
    datas = mDBM.do_select(strsql)
    if datas:
        reStatus = 0
        reMsg = '该区域下配置了通道,请先删除通道后,再删除区域!'
    else:
        strsql = f"delete from area where id={area_id};"
        ret = mDBM.do_sql(strsql)
        if ret == True:
            reStatus = 1
            reMsg = '删除区域成功'
        else:
            reStatus = 0
            reMsg = '删除区域失败,请联系技术支持!'
    return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/area/add',methods=['POST'])
@login_required
async def channel_area_add(): #添加区域
    json_data = await request.get_json()
    area_name = json_data.get('name')
    strsql = f"select id from area where area_name='{area_name}';"
    data = mDBM.do_select(strsql,1)
    if data:
        reStatus = 0
        reMsg = '区域名称重复,请修改!'
    else:
        strsql = f"insert into area (area_name) values ('{area_name}');"
        ret = mDBM.do_sql(strsql)
        if ret == True:
            reStatus = 1
            reMsg = '新增区域成功'
        else:
            reStatus = 0
            reMsg = '新增区域失败,请联系技术支持!'
    return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/model/list',methods=['GET'])
@login_required
async def channel_model_list(): #获取算法列表
    strsql = "select ID,model_name,version from model;"
    datas = mDBM.do_select(strsql)
    reMsg = {}
    if datas:
        reMsg = [{'ID': data[0], 'model_name': data[1],'version':data[2]} for data in datas]
    return jsonify(reMsg)


@api.route('/channel/model/linkmodel',methods=['POST'])    #--没调用。。
@login_required
async def channel_model_linkmodel(): #获取算法列表 --关联算法时展示 #?关联算法时需要初始化布防计划,同样删除的需要删除
    channel_id = (await request.form)['channel_id']
    model_list = json.loads((await request.form)['model_list'])
    #? 需要对channel_id和model_list的是否在数据库要进行一个检查
    reStatus = 0
    reMsg = '提交的参数错误,请检查!'
    strsql = f"select ID from channel where ID={channel_id};"
    if mDBM.do_select(strsql,1):    #通道号在数据库中
        for model_id in model_list:
            strsql = f"select ID from model where ID = {model_id};"
            if not mDBM.do_select(strsql,1):
                return jsonify({'status': reStatus, 'msg': reMsg})
        ret =mDBM.updateC2M(channel_id,model_list)
        if ret == True:
            reStatus = 1
            reMsg = '修改关联算法成功'
        else:
            reStatus = 0
            reMsg = '修改关联算法失败,请联系技术支持!'
    return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/model/getarea',methods=['GET'])
@login_required
async def channel_model_getarea(): #获取算法区域的备注信息 --- 同时获取检测阈值
    ID = request.args.get('ID')
    strsql = f"select check_area,polygon,conf_threshold from channel2model where ID={ID};"
    data = mDBM.do_select(strsql,1)
    if data:
        reMsg = {'ID':ID,'check_area':data[0],'polygon':data[1],'conf_threshold':data[2]}
    else:
        reMsg = {}
    return jsonify(reMsg)

@api.route('/channel/model/changearea',methods=['POST'])
@login_required
async def channel_model_changearea(): #修改算法检测区域信息
    ID = (await request.form)['ID']
    check_area = (await request.form)['check_area']
    check_x = (await request.form)['polygon']
    strsql = (f"update channel2model set check_area={check_area},polygon={check_x} where ID={ID};")
    ret = mDBM.do_sql(strsql)
    if ret == True:
        reStatus = 1
        reMsg = '修改算法检测区域成功'
        #需要重启视频通道的执行程序 --需要cid
        #?
    else:
        reStatus = 0
        reMsg = '新修改算法检测区域失败,请联系技术支持!'
    return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/model/changethreshold',methods=['POST'])
@login_required
async def channel_model_changthreshold(): #修改算法阈值
    ID = (await request.form)['ID']
    conf_threshold = (await request.form)['conf_threshold']

    strsql = (f"update channel2model set conf_threshold={conf_threshold} where ID={ID};")
    ret = mDBM.do_sql(strsql)
    if ret == True:
        reStatus = 1
        reMsg = '修改算法的阈值成功'
    else:
        reStatus = 0
        reMsg = '新修改算法的阈值失败,请联系技术支持!'
    return jsonify({'status': reStatus, 'msg': reMsg})

@api.route('/channel/model/getschedule',methods=['GET'])
@login_required
async def channel_model_getschedule(): #获取算法的布防时间
    ID = request.args.get('ID')
    strsql = f"select day,hour,status from schedule where channel2model_id={ID};"
    datas = mDBM.do_select(strsql)
    if datas:
        reMsg = [{'day': data[0], 'hour': data[1],'status':data[2]} for data in datas]
    else:
        reMsg = {}
    return jsonify(reMsg)

@api.route('/channel/model/changeschedule',methods=['POST'])
@login_required
async def channel_model_changeschedule(): #修改算法的布防时间
    ID = (await request.form)['ID']
    schedule_data_str = (await request.form)['schedule_data']
    schedule_data = json.loads(schedule_data_str.replace("'", '"'))
    for day,hours in schedule_data.items():
        for hour,status in enumerate(hours):
            strsql = (f"insert into schedule (channel2model_id,day,hour,status) values ({ID},'{day}',{hour},{status})"
                      f" on conflict(channel2model_id,day,hour) do update set status=excluded.status;")
            ret = mDBM.do_sql(strsql)
            if ret == False:
                reStatus = 0
                reMsg = '修改监测区域失败,请联系技术支持!'
                return jsonify({'status': reStatus, 'msg': reMsg})
    reStatus = 1
    reMsg = '修改监测区域成功'
    return jsonify({'status': reStatus, 'msg': reMsg})