#!E:\Pycharm Projects\Waytous
# -*- coding: utf-8 -*-
# @Time : 2022/10/18 12:32
# @Author : Opfer
# @Site :
# @File : submit.py    
# @Software: PyCharm
import json
import uuid
from typing import List

from core.group import CurrentTruck, Group
from core.util import POST
from data.dispatchInfo import DispatchInfo
from data.para_config import get_value
from equipment import DumpInfo, ExcavatorInfo, TruckInfo
from graph.topo_graph import Topo
from settings import get_logger, redis5
from tables import session_mysql, DispatchSetting
from core.group import truck_direct2redis


class DispatchSubmission:
    """ class for the submission calculated dispatch.

    Description:
        将调度结果按照指定格式传递到云端机群
    Attribute:

    """
    def __init__(self, dump: DumpInfo, excavator: ExcavatorInfo, truck: TruckInfo, topo: Topo):
        self.logger = get_logger("zxt.submission")
        self.dump = dump
        self.excavator = excavator
        self.truck = truck
        self.topo = topo

    def truck_dispatch_to_redis(self, truck_id: str, truck_info: CurrentTruck, dispatch_seq: List[int], group_mode: int):
        """
        将truck_id对应矿卡派车计划写入redis
        :param group_mode: (int)
        :param truck_id: (uuid) 矿卡uuid
        :param truck_info: (object)
        :param dispatch_seq: (List[int]) 矿卡派车计划
        :return: None
        """

        self.logger.info(f'调度车辆编号 {get_value("truck_uuid_to_name_dict")[truck_id]} {truck_id}')
        self.logger.info(f'车辆任务 {truck_info.get_task()}')
        self.logger.info(f'配对挖机 {dispatch_seq[0]}')
        self.logger.info(f'配对卸点 {dispatch_seq[1]}')

        # try:

        if truck_id not in DispatchInfo.truck_group_dict:
            group_id = None
            self.logger.error(f'调度结果写入异常-读取矿卡 {truck_id} 所在分组信息异常')
        else:
            group_id = DispatchInfo.truck_group_dict[truck_id]

        record = {"truckId": truck_id}

        # if group_id is None or DispatchInfo.get_group_mode(group_id) is None:
        #     group_mode = 3
        #     self.logger.error("调度模式读取异常-设置为固定派车模式")
        # else:
        #     group_mode = DispatchInfo.get_group_mode(group_id)

        self.logger.info(f'调度模式 {group_mode}')

        if group_mode == 3:
            self.logger.info("固定派车模式")
            self.fixed_dispatch_mode(group_id, truck_id)
        else:
            self.logger.info("动态调度模式")
            self.dynamic_dispatch_mode(dispatch_seq, group_id, record, truck_info.get_sate(),
                                       truck_info.get_task(), truck_id)

        # except Exception as es:
        #     self.logger.error("调度结果写入异常")
        #     self.logger.error(f"调度结果:{dispatch_seq}")
        #     self.logger.error(es)

    def dynamic_dispatch_mode(self, dispatch_seq, group_id, record, state, task, truck_id):
        """
        write dispatch plan in dynamic dispatch mode.
        :param dispatch_seq:
        :param group_id:
        :param record:
        :param state:
        :param task:
        :param truck_id:
        :return:
        """
        if (task in [1, 2]) or (task == 3 and state == 2):  # 车辆位于装载区，或车辆重载等待

            if task in [1, 2]:
                self.logger.info(f'车辆 {truck_id} 装载区调度')
            else:
                self.logger.info(f'车辆 {truck_id} 重载二次调度')

            # 查询车辆相关派车计划 dispatch_seq[next_excavator_id, next_unload_area_id]
            if dispatch_seq[1] is None or (dispatch_seq[1] not in DispatchInfo.unload_area_dump_dict):
                # 无法查询到目标卸载点
                item = (session_mysql.query(DispatchSetting).filter_by(group_id=group_id, isdeleted=0, ).first())
            else:
                dump_id = DispatchInfo.unload_area_dump_dict[dispatch_seq[1]]
                try:
                    item = (session_mysql.query(DispatchSetting).filter_by(dump_id=dump_id, group_id=group_id,
                                                                           isdeleted=0, ).first())
                    if item is None:
                        raise Exception(f'车辆 {truck_id} 无法找到派车计划 {dump_id} {group_id}')
                    if dispatch_seq[0] is None:
                        raise Exception("调度计划挖机与实时监控不匹配")
                except Exception as es:
                    item = (session_mysql.query(DispatchSetting).filter_by(group_id=group_id, isdeleted=0, ).first())
                    self.logger.error(es)

            # 其余调度信息写入
            # try:

            record = redis_format(truck_id, group_id, str(uuid.uuid1()), item)

            # TODO:
            # 判断了两次是否拥堵，需要改善

            if self.topo is not None:

                # 车辆重载等待，且前方道路阻塞
                if task == 3 and state == 2 and truck_id in self.truck.get_truck_locate_dict() and \
                        self.truck.get_truck_locate_dict()[truck_id] in self.topo.cross_bf_lanes:
                    # try:
                    # if truck_id in self.truck.truck_is_temp and not self.truck.truck_is_temp[truck_id]:
                    self.logger.info("二次调度前往卸载区")
                    record["isTemp"] = True  # 避免反复修改
                    POST(truck_id)
                    # else:
                    #     self.logger.info("车辆已完成二次调度-无需更改派车计划")

                    # except Exception as es:
                    #     self.logger.error(es)
                    #     self.logger.error("二次调度失败")
                    #     record["isTemp"] = False
                    #     redis5.set(truck_id, str(json.dumps(record)))
                else:
                    self.logger.info("正常调度前往卸载区")
                    record["isTemp"] = False

            self.logger.info(f'redis 注入 {record}')
            redis5.set(truck_id, str(json.dumps(record)))

            # self.logger.error("调度结果写入异常-矿卡空载")

        elif (task in [-2, 4, 5]) or (task == 0 and state == 2):  # 车辆位于备停区或位于卸载区，或车辆空载等待

            if task == -2:
                self.logger.info(f'车辆 {truck_id} 备停区调度')
            elif task in [4, 5]:
                self.logger.info(f'车辆 {truck_id} 卸载区调度')
            else:
                self.logger.info(f'车辆 {truck_id} 空载二次调度')

            # 查询车辆相关派车计划 dispatch_seq[next_excavator_id, next_unload_area_id]
            if dispatch_seq[0] is None:
                # 无法查询到目标挖机
                item = (session_mysql.query(DispatchSetting).filter_by(group_id=group_id, isdeleted=0, ).first())
            else:
                excavator_id = dispatch_seq[0]
                try:
                    item = (session_mysql.query(DispatchSetting).filter_by(exactor_id=excavator_id, group_id=group_id,
                                                                           isdeleted=0, ).first())

                    if item is None:
                        raise Exception(f' 车辆 {truck_id} 无法找到派车计划 {excavator_id} {group_id}')
                    if dispatch_seq[0] is None:
                        raise Exception("调度计划挖机与实时监控不匹配")
                except Exception as es:
                    item = (session_mysql.query(DispatchSetting).filter_by(group_id=group_id, isdeleted=0, ).first())
                    self.logger.error(es)

            # 调度信息写入
            # try:
            record = redis_format(truck_id, group_id, str(uuid.uuid1()), item)

            if self.topo is not None:

                # 车辆重载等待，且前方道路阻塞
                if task == 0 and state == 2 and truck_id in self.truck.get_truck_locate_dict() and \
                        self.truck.get_truck_locate_dict()[truck_id] in self.topo.cross_bf_lanes:
                    # 车辆停车等待
                    # try:
                    # if truck_id in self.truck.truck_is_temp and not self.truck.truck_is_temp[truck_id]:
                    self.logger.info("二次调度前往装载区")
                    record["isTemp"] = True  # 避免反复修改
                    POST(truck_id)
                    # else:
                    #     self.logger.info("车辆已完成二次调度-无需更改派车计划")
                    # except Exception as es:
                    #     self.logger.error(es)
                    #     self.logger.error("二次调度失败")
                    #     record["isTemp"] = False
                    #     redis5.set(truck_id, str(json.dumps(record)))

                else:
                    self.logger.info("正常调度前往装载区")
                    record["isTemp"] = False

            self.logger.info(f'redis 注入 {record}')
            redis5.set(truck_id, str(json.dumps(record)))

            # self.logger.error("调度结果写入异常-矿卡重载")
        else:
            pass

    def fixed_dispatch_mode(self, group_id, truck_id):
        """
        write dispatch plan in fixed dispatch method.
        :param group_id:
        :param record:
        :param truck_id:
        :return:
        """
        item = session_mysql.query(DispatchSetting).filter_by(truck_id=truck_id, isdeleted=0, ).first()

        if item is None:
            self.logger.error(f'车辆 {truck_id} 无派车计划-无法执行固定派车')
            return
        record = redis_format(truck_id, group_id, item.id, item)

        self.logger.info(f'redis 注入 {record}')
        redis5.set(truck_id, str(json.dumps(record)))

    def group_dispatch_to_redis(self, group: Group, dispatch_plan_dict):
        """
        Update the dispatch plan in the group to redis
        :param group: (Group)
        :param dispatch_plan_dict: (Dict)
        :return: None
        """

        self.logger.info(f'调度分组: {group.group_id} {DispatchInfo.group_name[group.group_id]}')
        self.logger.info(f'组内车辆 {group.group_trucks}')
        self.logger.info(f'组内挖机 {group.group_excavators}')
        self.logger.info(f'组内卸点 {group.group_dumps}')
        self.logger.info(f'调度模式 {group.group_mode}')
        self.logger.info("dispatch_plan_dict")
        self.logger.info(dispatch_plan_dict)


        for truck_id, dispatch_plan in dispatch_plan_dict.items():
            try:
                self.logger.info(f'======================================= 调度车辆 =======================================')
                self.truck_dispatch_to_redis(truck_id, group.truck_info_list[truck_id], dispatch_plan, group.group_mode)
                self.logger.info("======================================== 完成写入 =======================================")
            except Exception as es:
                self.logger.error("group_dispatch_to_redis_error")
                self.logger.error(es)
                truck_direct2redis(truck_id)



def redis_format(truck_id, group_id, dispatch_id, item):
    record = {"truckId": truck_id, "dispatchId": dispatch_id, "exactorId": item.exactor_id, "dumpId": item.dump_id,
              "loadAreaId": item.load_area_id, "unloadAreaId": item.unload_area_id, "groupId": item.group_id,
              "isdeleted": False, "isTemp": False, "haulFlag": -1, "groupName": DispatchInfo.group_name[group_id]}
    return record