#!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)

    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
        """
        for group_id in DispatchInfo.group_dump_dict.keys():
            group = Group(group_id, self.truck, self.pre_sch)
            self.group_list.append(group)

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

    def group_dispatch(self):
        """
        Group dispatching logic.
        :return:
        """
        for group in self.group_list:
            truck_dispatch_plan_dict = group.group_dispatch(ExpectedTime)
            print("truck_dispatch_plan_dict")
            print(truck_dispatch_plan_dict)
            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 = 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(DispatchMatch)
                    #         .filter_by(dump_id=dispatch_seq[1],
                    #                    exactor_id=dispatch_seq[0],
                    #                    truck_id=truck_id,
                    #                    group_id=group_id,
                    #                    isauto=1, isdeleted=0, ).first())

                    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,
                                       isauto=1, isdeleted=0, ).first())

                    # item = (
                    #     session_mysql.query(DispatchEquipment.id, DispatchMatch.load_area_id, DispatchMatch.unload_area_id, DispatchMatch.dump_id, DispatchEquipment.isdeleted).
                    #         join(DispatchEquipment, DispatchMatch.match_code == DispatchEquipment.match_code).
                    #         filter(DispatchMatch.exactor_id == dispatch_seq[0],
                    #                DispatchMatch.dump_id == dispatch_seq[1],
                    #                DispatchEquipment.equipment_id == truck_id,
                    #                DispatchMatch.id == group_id
                    #                ).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,
                                       isauto=1, isdeleted=0, ).first())

                    # item = (
                    #     session_mysql.query(DispatchEquipment.id, DispatchMatch.load_area_id, DispatchMatch.unload_area_id, DispatchMatch.dump_id, DispatchEquipment.isdeleted).
                    #         join(DispatchEquipment, DispatchMatch.match_code == DispatchEquipment.match_code).
                    #         filter(DispatchEquipment.equipment_id == truck_id,
                    #                DispatchMatch.id == group_id
                    #                ).first())

                try:
                    # record["exactorId"] = item.exactor_id
                    # record["dumpId"] = item.dump_id
                    # record["loadAreaId"] = item.load_area_id
                    # record["unloadAreaId"] = item.unload_area_id
                    # record["dispatchId"] = item.id
                    # record["isdeleted"] = False
                    # record["creator"] = item.creator
                    # record["createtime"] = item.createtime.strftime(
                    #     "%b %d, %Y %I:%M:%S %p")

                    record["id"] = 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]

                    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,
                                       isauto=1, isdeleted=0, ).first())

                    # item = (
                    #     session_mysql.query(DispatchEquipment.id, DispatchMatch.load_area_id, DispatchMatch.unload_area_id, DispatchMatch.dump_id, DispatchEquipment.isdeleted).
                    #         join(DispatchEquipment, DispatchMatch.match_code == DispatchEquipment.match_code).
                    #         filter(DispatchMatch.exactor_id == dispatch_seq[0],
                    #                DispatchMatch.dump_id == dispatch_seq[1],
                    #                DispatchEquipment.equipment_id == truck_id,
                    #                DispatchMatch.id == group_id
                    #                ).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,
                                       isauto=1, isdeleted=0, ).first())

                    # item = (
                    #     session_mysql.query(DispatchEquipment.id, DispatchMatch.load_area_id, DispatchMatch.unload_area_id, DispatchMatch.dump_id, DispatchEquipment.isdeleted).
                    #         join(DispatchEquipment, DispatchMatch.match_code == DispatchEquipment.match_code).
                    #         filter(DispatchEquipment.equipment_id == truck_id,
                    #                DispatchMatch.id == group_id
                    #                ).first())

                try:
                    # record["exactorId"] = self.excavator.excavator_index_to_uuid_dict[dispatch_seq[1]]
                    # record["dumpId"] = item.dump_id
                    # record["loadAreaId"] = item.load_area_id
                    # record["unloadAreaId"] = item.unload_area_id
                    # record["dispatchId"] = item.id
                    # record["isdeleted"] = False
                    # record["creator"] = item.creator
                    # record["createtime"] = item.createtime.strftime(
                    #     "%b %d, %Y %I:%M:%S %p")

                    record["id"] = 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]

                    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,
                                           isauto=1, isdeleted=0).first())

                        # item = (
                        #     session_mysql.query(DispatchEquipment.id, DispatchMatch.load_area_id, DispatchMatch.unload_area_id, DispatchMatch.dump_id, DispatchEquipment.isdeleted).
                        #         join(DispatchEquipment, DispatchMatch.match_code == DispatchEquipment.match_code).
                        #         filter(DispatchMatch.exactor_id==dispatch_seq[0],
                        #                    DispatchEquipment.equipment_id==truck_id,
                        #                    # DispatchMatch.group_code==group_id
                        #                ).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,
                                           isauto=1, isdeleted=0).first())

                        # item = (
                        #     session_mysql.query(DispatchEquipment.id, DispatchMatch.load_area_id, DispatchMatch.unload_area_id, DispatchMatch.dump_id, DispatchEquipment.isdeleted).
                        #         join(DispatchEquipment, DispatchMatch.match_code == DispatchEquipment.match_code).
                        #         filter(DispatchEquipment.equipment_id == truck_id,
                        #                DispatchMatch.id == group_id
                        #                ).first())

                    try:
                        # record["exactorId"] = item.exactor_id
                        # record["dumpId"] = item.dump_id
                        # record["loadAreaId"] = item.load_area_id
                        # record["unloadAreaId"] = item.unload_area_id
                        # record["dispatchId"] = item.id
                        # record["isdeleted"] = False
                        # record["creator"] = item.creator
                        # record["createtime"] = item.createtime.strftime(
                        #     "%b %d, %Y %I:%M:%S %p")

                        record["id"] = 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
        """
        for truck_id, dispatch_plan in dispatch_plan_dict.items():
            self.truck_dispatch_to_redis(truck_id, dispatch_plan)

