import re
import typing
from enum import Enum

from dcs.mapping import *
from dcs.terrain import Airport
from dcs.ships import CVN_74_John_C__Stennis, LHA_1_Tarawa, CV_1143_5_Admiral_Kuznetsov

from game import db
from gen.ground_forces.combat_stance import CombatStance
from .theatergroundobject import TheaterGroundObject


class ControlPointType(Enum):
    AIRBASE = 0                # An airbase with slot for everything
    AIRCRAFT_CARRIER_GROUP = 1 # A group with a Stennis type carrier (F/A-18, F-14 compatible)
    LHA_GROUP = 2              # A group with a Tarawa carrier (Helicopters & Harrier)
    FARP = 4                   # A FARP, with slots for helicopters
    FOB = 5                    # A FOB (ground units only)


class ControlPoint:

    id = 0
    position = None  # type: Point
    name = None  # type: str
    full_name = None  # type: str
    base = None  # type: theater.base.Base
    at = None  # type: db.StartPosition
    icls = 1

    connected_points = None  # type: typing.List[ControlPoint]
    ground_objects = None  # type: typing.List[TheaterGroundObject]

    captured = False
    has_frontline = True
    frontline_offset = 0.0
    cptype: ControlPointType = None

    ICLS_counter = 1
    alt = 0

    def __init__(self, id: int, name: str, position: Point, at, radials: typing.Collection[int], size: int, importance: float,
                 has_frontline=True, cptype=ControlPointType.AIRBASE):
        import theater.base

        self.id = id
        self.name = " ".join(re.split(r" |-", name)[:2])
        self.full_name = name
        self.position = position
        self.at = at
        self.ground_objects = []
        self.ships = []

        self.size = size
        self.importance = importance
        self.captured = False
        self.has_frontline = has_frontline
        self.radials = radials
        self.connected_points = []
        self.base = theater.base.Base()
        self.cptype = cptype
        self.stances = {}
        self.tacanY = False
        self.tacanN = None
        self.tacanI = "TAC"
        self.icls = 0
        self.airport = None

    @classmethod
    def from_airport(cls, airport: Airport, radials: typing.Collection[int], size: int, importance: float, has_frontline=True):
        assert airport
        obj = cls(airport.id, airport.name, airport.position, airport, radials, size, importance, has_frontline, cptype=ControlPointType.AIRBASE)
        obj.airport = airport()
        return obj

    @classmethod
    def carrier(cls, name: str, at: Point, id: int = 1001):
        import theater.conflicttheater
        cp = cls(id, name, at, at, theater.conflicttheater.LAND, theater.conflicttheater.SIZE_SMALL, 1,
                   has_frontline=False, cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP)
        cp.tacanY = False
        cp.tacanN = random.randint(26, 49)
        cp.tacanI = random.choice(["STE", "CVN", "CVH", "CCV", "ACC", "ARC", "GER", "ABR", "LIN", "TRU"])
        ControlPoint.ICLS_counter = ControlPoint.ICLS_counter + 1
        cp.icls = ControlPoint.ICLS_counter
        return cp

    @classmethod
    def lha(cls, name: str, at: Point, id: int = 1002):
        import theater.conflicttheater
        cp = cls(id, name, at, at, theater.conflicttheater.LAND, theater.conflicttheater.SIZE_SMALL, 1,
                   has_frontline=False, cptype=ControlPointType.LHA_GROUP)
        cp.tacanY = False
        cp.tacanN = random.randint(1,25)
        cp.tacanI = random.choice(["LHD", "LHA", "LHB", "LHC", "LHD", "LDS"])
        return cp

    @property
    def heading(self):
        if self.cptype == ControlPointType.AIRBASE:
            return self.airport.runways[0].heading
        elif self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]:
            return 0 # TODO compute heading
        else:
            return 0

    def __str__(self):
        return self.name

    @property
    def is_global(self):
        return not self.connected_points

    @property
    def is_carrier(self):
        return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]

    @property
    def is_fleet(self):
        return self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]

    @property
    def is_lha(self):
        return self.cptype in [ControlPointType.LHA_GROUP]

    @property
    def sea_radials(self) -> typing.Collection[int]:
        # TODO: fix imports
        all_radials = [0, 45, 90, 135, 180, 225, 270, 315, ]
        result = []
        for r in all_radials:
            if r not in self.radials:
                result.append(r)
        return result

    def connect(self, to):
        self.connected_points.append(to)
        self.stances[to.id] = CombatStance.DEFENSIVE

    def has_runway(self):
        """
        Check whether this control point can have aircraft taking off or landing.
        :return:
        """
        if self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP] :
            for g in self.ground_objects:
                if g.dcs_identifier in ["CARRIER", "LHA"]:
                    for group in g.groups:
                        for u in group.units:
                            if db.unit_type_from_name(u.type) in [CVN_74_John_C__Stennis, LHA_1_Tarawa, CV_1143_5_Admiral_Kuznetsov]:
                                return True
            return False
        elif self.cptype in [ControlPointType.AIRBASE, ControlPointType.FARP]:
            return True
        else:
            return True

    def get_carrier_group_name(self):
        """
        Get the carrier group name if the airbase is a carrier
        :return: Carrier group name
        """
        if self.cptype in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP] :
            for g in self.ground_objects:
                if g.dcs_identifier == "CARRIER":
                    for group in g.groups:
                        for u in group.units:
                            if db.unit_type_from_name(u.type) in [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov]:
                                return group.name
                elif g.dcs_identifier == "LHA":
                    for group in g.groups:
                        for u in group.units:
                            if db.unit_type_from_name(u.type) in [LHA_1_Tarawa]:
                                return group.name
        return None

    def is_connected(self, to) -> bool:
        return to in self.connected_points

    def find_radial(self, heading: int, ignored_radial: int = None):
        closest_radial = 0
        closest_radial_delta = 360
        for radial in [x for x in self.radials if x != ignored_radial]:
            delta = math.fabs(radial - heading)
            if delta < closest_radial_delta:
                closest_radial = radial
                closest_radial_delta = delta

        return closest_radial

    def find_ground_objects_by_obj_name(self, obj_name):
        found = []
        for g in self.ground_objects:
            if g.obj_name == obj_name:
                found.append(g)
        return found

