#!E:\Pycharm Projects\Waytous
# -*- coding: utf-8 -*-
# @Time : 2022/6/1 16:35
# @Author : Opfer
# @Site :
# @File : dispatcher.py    
# @Software: PyCharm

from data.dispatchInfo import DispatchInfo
from core.group import Group
from alg.algorithm import ExpectedTime
from settings import get_logger, session_mysql, redis5
from tables import Dispatch, DispatchMatch, DispatchEquipment, DispatchGroup, DispatchSetting
from para_config import DeviceMap, get_value, global_period_para_update
from equipment import TruckInfo, ExcavatorInfo, DumpInfo
from core.schedule import PreSchedule
import json
import numpy as np
from datetime import datetime, timedelta


class Dispatcher:
    """
    class for group dispatch program.
    """
    def __init__(self, truck: TruckInfo, dump: DumpInfo, excavator: ExcavatorInfo, pre_sch: PreSchedule, request_mode=False):
        self.group_list = {}
        self.truck = truck
        self.dump = dump
        self.excavator = excavator
        self.pre_sch = pre_sch
        self.request_mode = request_mode
        self.submission = DispatchSubmission(dump, excavator, truck)
        self.logger = get_logger("zxt.dispatcher")

    def period_update(self):
        """
        Update global parameter and equipment information.
        :return: None
        """

        # global_period_para_update()

        self.dump.dump_para_period_update()
        self.excavator.excavator_para_period_update()
        self.truck.truck_para_period_update(self.dump, self.excavator)
        self.truck.state_period_update()

    def group_generate(self):
        """
        Generate and initialize dispatch groups.
        :return: None
        """
        self.group_list = {}
        groups = DispatchInfo.get_all_group()
        for group_id in groups:
            if group_id not in self.group_list:
                group = Group(group_id, self.truck, self.pre_sch)
                self.group_list[group_id] = group

    def group_info_update(self):
        """
        Update group information.
        :return: None
        """
        for group in self.group_list.values():
            group.info_update()

    def group_dispatch(self):
        """
        Group dispatching logic.
        :return:
        """
        a = len(self.group_list)
        aa = self.group_list
        for group in self.group_list.values():

            try:

                truck_dispatch_plan_dict = group.group_dispatch(ExpectedTime)

            except Exception as es:
                self.logger.error(es)
                self.logger.error(f'分组{group.group_id} 调度异常')

            self.logger.info(f'调度分组: {group.group_id} {DispatchInfo.group_name[group.group_id]}')
            self.submission.group_dispatch_to_redis(group, truck_dispatch_plan_dict)


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

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

    """
    def __init__(self, dump, excavator, truck):
        self.logger = get_logger("zxt.submission")
        self.dump = dump
        self.excavator = excavator
        self.truck = truck

    def truck_dispatch_to_redis(self, truck_id, dispatch_seq):
        """
        将truck_id对应矿卡派车计划写入redis
        :param truck_id: (uuid) 矿卡uuid
        :param dispatch_seq: (List[int]) 矿卡派车计划
        :return: None
        """
        try:
            try:
                # group_id = self.group.dispatch_truck_group[truck_id]
                group_id = DispatchInfo.truck_group_dict[truck_id]

                record = {"truckId": truck_id}
                task = self.truck.get_truck_current_task()[truck_id]
            except Exception as es:
                self.logger.error("调度结果写入异常-读取矿卡信息异常(uuid, group id, task)")
                self.logger.error(es)

            if task in [0, 1, 2]:  # 卡车空载或在装载区出场前, 可变更卸载目的地
                try:
                    item = (
                        session_mysql.query(DispatchSetting)
                            .filter_by(
                                        # exactor_id=dispatch_seq[0],
                                       # dump_id=dispatch_seq[1],
                                       truck_id=truck_id,
                                       group_id=group_id,
                                        isdeleted=0, ).first())

                    if item is None:
                        raise Exception("调度计划表与实时监控不匹配")
                except Exception as es:
                    self.logger.error(es)
                    item = (
                        session_mysql.query(DispatchSetting)
                            .filter_by(truck_id=truck_id,
                                       # group_id=group_id,
                                       isdeleted=0, ).first())
                try:

                    record["dispatchId"] = item.id
                    record["exactorId"] = item.exactor_id
                    record["dumpId"] = DispatchInfo.unload_area_dump_dict[dispatch_seq[1]]
                    record["loadAreaId"] = item.load_area_id
                    record["unloadAreaId"] = item.unload_area_id
                    record["groupId"] = group_id
                    record["isdeleted"] = False
                    record["isTemp"] = False
                    record["haulFlag"] = -1
                    record["groupName"] = DispatchInfo.group_name[group_id]

                    self.logger.info(f'redis 注入 {record}')

                    redis5.set(truck_id, str(json.dumps(record)))
                except Exception as es:
                    self.logger.error("调度结果写入异常-矿卡空载")
            elif task in [3, 4, 5]:  # 卡车重载或在卸载区出场前, 可变更装载目的地
                try:

                    item = (
                        session_mysql.query(DispatchSetting)
                            .filter_by(
                                        # exactor_id=dispatch_seq[0],
                                       # dump_id=dispatch_seq[1],
                                       truck_id=truck_id,
                                       group_id=group_id,
                                       isdeleted=0, ).first())
                    if item is None:
                        raise Exception("调度计划表与实时监控不匹配")
                except Exception as es:
                    self.logger.error(es)
                    item = (
                        session_mysql.query(DispatchSetting)
                            .filter_by(truck_id=truck_id,
                                       # group_id=group_id,
                                       isdeleted=0, ).first())
                try:
                    record["dispatchId"] = item.id
                    record["exactorId"] = dispatch_seq[0]
                    record["dumpId"] = item.dump_id
                    record["loadAreaId"] = item.load_area_id
                    record["unloadAreaId"] = item.unload_area_id
                    record["groupId"] = group_id
                    record["isdeleted"] = False
                    record["isTemp"] = False
                    record["haulFlag"] = -1
                    record["groupName"] = DispatchInfo.group_name[group_id]

                    self.logger.info(f'redis 注入 {record}')

                    redis5.set(truck_id, str(json.dumps(record)))
                except Exception as es:
                    self.logger.error("调度结果写入异常-矿卡重载")
            elif task == -2:
                try:
                    try:
                        item = (
                                session_mysql.query(DispatchSetting)
                                    .filter_by(
                                               # exactor_id=dispatch_seq[0],
                                               truck_id=truck_id,
                                               group_id=group_id,
                                               isdeleted=0).first())

                        if item is None:
                            raise Exception("调度计划表与实时监控不匹配")

                        # self.logger.info(dispatch_seq[1])
                        # self.logger.info(DeviceMap.excavator_index_to_uuid_dict[dispatch_seq[1]])

                        # print("item")
                        # print(item.id, item.truck_id, item.exactor_id, item.dump_id)
                    except Exception as es:
                        self.logger.error(es)
                        item = (
                            session_mysql.query(DispatchSetting)
                                .filter_by(truck_id=truck_id,
                                           # group_id=group_id,
                                           isdeleted=0).first())

                    try:

                        record["dispatchId"] = item.id
                        record["exactorId"] = dispatch_seq[0]
                        record["dumpId"] = item.dump_id
                        record["loadAreaId"] = item.load_area_id
                        record["unloadAreaId"] = item.unload_area_id
                        record["groupId"] = group_id
                        record["isdeleted"] = False
                        record["isTemp"] = False
                        record["haulFlag"] = -1
                        record["groupName"] = DispatchInfo.group_name[group_id]

                        self.logger.info(f'redis 注入 {record}')

                        # record["createtime"] = datetime.now().strftime(
                        #     "%b %d, %Y %I:%M:%S %p")

                        redis5.set(truck_id, str(json.dumps(record)))

                    except Exception as es:
                        self.logger.error("调度结果写入异常-矿卡故障或备停区-redis写入异常")
                        self.logger.error(es)

                except Exception as es:
                    self.logger.error("调度结果写入异常-矿卡故障或备停区")
                    self.logger.error(es)
            else:
                pass

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

    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
        """
        aa = dispatch_plan_dict
        for truck_id, dispatch_plan in dispatch_plan_dict.items():
            self.logger.info(f'======================================= 调度车辆 =======================================')
            self.logger.info(f'矿车编号 {get_value("truck_uuid_to_name_dict")[truck_id]} {truck_id}')
            self.logger.info(f'车辆任务 {group.truck_info_list[truck_id].get_task()}')
            self.logger.info(f'配对挖机 {dispatch_plan[0]}')
            self.logger.info(f'配对卸点 {dispatch_plan[1]}')
            self.truck_dispatch_to_redis(truck_id, dispatch_plan)
            self.logger.info("======================================== 完成写入 =======================================")

