# -*- coding:utf-8 -*-
# author: Jiang

"""
想定：尤卡坦冲突-接口调用示例想定
红方智能体
创建任务、分配单元到任务和设置任务，以及设置各级别条令智能体
备注：此智能体仅为态势处理和接口调用示例，而非有效红方策略。
"""

import logging
from engine.LingYi.entitys.global_util import *
from engine.LingYi.entitys.agent_base import RuleAgentBase
from engine.LingYi.entitys import geo

logger = logging.getLogger("UnitAgent")
logger.setLevel(level=logging.INFO)
formatter_play = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                                   datefmt="%Y-%m-%d %H:%M:%S")
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter_play)
logger.propagate = False
logger.addHandler(console)


class Agent(RuleAgentBase):
    def __init__(self, side_name, params):
        RuleAgentBase.__init__(self, side_name)
        logger.info('%s:%s play game' % (side_name, self.__class__.__name__))
        self.step_index = 0
        self.weather_raining = None  # 想定天气降雨情况
        self.weather_fur = None  # 想定中天气的云量
        self.anti_sub_name = "反潜-苍龙"  # 反潜任务名
        self.anti_sub_mission = None  # 东部反潜任务
        self.last_sonar_time = -1  # 还上次投送声纳时间
        self.anti_sub_air_status = 0  # 反潜机状态
        self.last_sonar_shadow = True  # 上次投放是浅层

    def weather_operation(self):
        # 获取添加的天气影响
        if self.weather_raining is None:
            if "RFR" in self.scenario.WeatherProfile:
                # 获取降雨率 影响激光损伤
                self.weather_raining = self.scenario.WeatherProfile["RFR"]
            if "FUR" in self.scenario.WeatherProfile:
                # 获取云量 影响激光损伤
                self.weather_fur = self.scenario.WeatherProfile["FUR"]

    def anti_submarine(self, time_elapse):
        """
        反潜
        :param time_elapse: int: 推演时间
        :return:
        """
        self.anti_sub_name = "反潜-苍龙"  # 反潜任务名
        if self.anti_sub_mission is None:
            self.anti_sub_mission = self.get_mission_by_name(self.anti_sub_name)  # 东部反潜任务
            if self.anti_sub_mission is None:
                anti_patrol = [(19.38, -82.57, 'ANS1'), (19.38, -81.37, 'ANS2'), (18.18, -81.37, 'ANS3'),
                               (18.18, -82.57, 'ANS4')]
                self.anti_sub_mission = self.create_patrol_mission(self.anti_sub_name, 
                                                                   MissionPatrolType.ANTI_SUBMARINE, anti_patrol)
                self.anti_sub_mission.doctrine_weapon_control_status_subsurface(WeaponControlStatus.Free)
                self.anti_sub_mission.set_one_third_rule(False)  # 设置巡逻任务不执行三分之一规则，不然不会全部飞机第一时间起飞
                # 设置任务不对巡逻区外的探测目标进行分析，不然会出巡逻区打击巡逻区外空中目标
                self.anti_sub_mission.patrol_checkOPA(False)
                self.anti_sub_mission.patrol_set_throttle_station(Throttle.Cruise)  # 巡逻任务飞机阵位油门
                self.anti_sub_mission.patrol_set_throttle_transit(Throttle.Cruise)  # 巡逻任务飞机出航油门
                self.anti_sub_mission.patrol_set_stationAltitude(150)  # 巡逻任务飞机阵位高度  因为鱼雷发射高度最高300米、
                self.anti_sub_mission.patrol_set_transitAltitude(200)  # 巡逻任务飞机出航高度
                self.anti_sub_mission.patrol_flight_size(FlightSize.One)  # 飞机单机编队

                airs_id = list(self.client_info['unit'].keys())  # 单元id列表
                if not airs_id:
                    airs_name = ["卡-27PL型 #2", "卡-27PL型 #3"]
                    for name in airs_name:
                        if name in self.units_of_name:
                            airs_id.append(self.units_of_name[name].ID)
                if airs_id:
                    self.assign_units_to_mission(airs_id, self.anti_sub_name)  # 注意单次分配单元任务不超过10架飞机
                    self.air_single_out(airs_id)  # 飞机起飞

        airs_id = list(self.client_info['unit'].keys())  # 单元id列表
        if not airs_id:
            airs_name = ["卡-27PL型 #2", "卡-27PL型 #3"]
            for name in airs_name:
                if name in self.units_of_name:
                    airs_id.append(self.units_of_name[name].ID)
        cang_position = (18.787, -81.944)
        if self.anti_sub_air_status == 0:
            # 还没有投放声纳, 两架反潜机首先弹蓝方苍老潜艇原先位置
            all_aircraft_in_air = True
            for air_id in airs_id:
                air = self.get_unit(air_id)
                if air is None:
                    continue
                air_status = air.get_status_type()
                if air_status == AirValidStatus.InAir:
                    # 只考虑在空飞机
                    air.plotted_course([cang_position])
                else:
                    all_aircraft_in_air = False
            if all_aircraft_in_air:
                self.anti_sub_air_status = 1
        elif self.anti_sub_air_status == 1:
            # 已设置反潜机航路
            for air_id in airs_id:
                air = self.get_unit(air_id)
                if air is None:
                    continue
                distance = geo.get_horizontal_distance(cang_position, (air.Lat, air.Lon))
                if distance < 20:
                    # 距离原潜艇位置20千米内时:
                    self.anti_sub_air_status = 2
        else:
            # 声纳探测距离3海里，飞机巡航速度110节，每飞3海里需时约98秒
            if time_elapse > self.last_sonar_time + 97:
                sonar_id = 2532  # 声纳ID
                for air_id in airs_id:
                    air = self.get_unit(air_id)
                    if air is None:
                        continue
                    weapon_info = air.get_weapon_info()
                    if sonar_id in weapon_info:
                        air.deploy_sonar("PASSIVE", self.last_sonar_shadow)  # 飞机投放声纳
                        self.last_sonar_time = time_elapse
                self.last_sonar_shadow = not self.last_sonar_shadow

    def initial(self, situation):
        """
        初始化函数，每局推演开始前被调用. 可用于任务创建、设置，条令设置，变量初始化等
        :param situation: tuple: units, contacts
        :return:
        """
        self.set_agent_decision_time(5)  # 客户端导入智能体设置决策间隔
        self.weather_operation()  # 获取添加的降雨情况
        self.anti_submarine(0)

    def step(self, time_elapse, situation):
        """
        # 每步决策函数
        :param time_elapse:  int, time elapse
        :param situation: tuple: units-list, contacts-list
        :return:
        """
        self.step_index += 1
        self.anti_submarine(time_elapse)  # 反潜

    def deduction_end(self):
        # agent结束后自动被调用函数， 可保存模型，比如记录本局策略后的得分等
        logging.info('%s:%s play game result:%d' % (self.Name, self.__class__.__name__, self.TotalScore))

    def is_done(self):
        # agent主动结束本局推演，比如一定胜利或失败后
        # 只能训练时调用此函数，比赛对战时此函数不可用
        return False
