from dcs.helicopters import helicopter_map

from ui.eventresultsmenu import *

from game import *
from game.event import *
from .styles import STYLES, RED


class EventMenu(Menu):
    scramble_entries = None  # type: typing.Dict[typing.Type[Task], typing.Dict[typing.Type[UnitType], typing.Tuple[Entry, Entry]]]
    ca_slot_entry = None  # type: Entry
    error_label = None  # type: Label
    awacs = None  # type: IntVar

    def __init__(self, window: Window, parent, game: Game, event: event.Event):
        super(EventMenu, self).__init__(window, parent, game)

        self.event = event
        self.scramble_entries = {k: {} for k in self.event.tasks}

        if self.event.attacker_name == self.game.player_name:
            self.base = self.event.departure_cp.base
        else:
            self.base = self.event.to_cp.base

        self.frame = self.window.right_pane
        self.awacs = IntVar()

    def display(self):
        self.window.clear_right_pane()
        row = 0

        def header(text, style="strong"):
            nonlocal row
            head = Frame(self.frame, **STYLES["header"])
            head.grid(row=row, column=0, sticky=N+EW, columnspan=5)
            Label(head, text=text, **STYLES[style]).grid()
            row += 1

        def label(text, _row=None, _column=None, columnspan=None, sticky=None):
            nonlocal row
            new_label = Label(self.frame, text=text, **STYLES["widget"])
            new_label.grid(row=_row and _row or row, column=_column and _column or 0, columnspan=columnspan, sticky=sticky)

            if _row is None:
                row += 1

            return new_label

        def scrable_row(task_type, unit_type, unit_count, client_slots: bool):
            nonlocal row
            Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count), **STYLES["widget"]).grid(row=row, sticky=W)

            scramble_entry = Entry(self.frame, width=2)
            scramble_entry.grid(column=1, row=row, sticky=E, padx=5)
            scramble_entry.insert(0, "0")
            Button(self.frame, text="+", command=self.scramble_half(task_type, unit_type), **STYLES["btn-primary"]).grid(column=2, row=row)

            if client_slots:
                client_entry = Entry(self.frame, width=2)
                client_entry.grid(column=3, row=row, sticky=E, padx=5)
                client_entry.insert(0, "0")
                Button(self.frame, text="+", command=self.client_one(task_type, unit_type), **STYLES["btn-primary"]).grid(column=4, row=row)
            else:
                client_entry = None

            self.scramble_entries[task_type][unit_type] = scramble_entry, client_entry

            row += 1

        # Header
        header("Mission Menu", "title")

        # Mission Description
        Label(self.frame, text="{}".format(self.event), **STYLES["mission-preview"]).grid(row=row, column=0, columnspan=5, sticky=S+EW, padx=5, pady=5)
        row += 1

        Label(self.frame, text="Amount", **STYLES["widget"]).grid(row=row, column=1, columnspan=2)
        Label(self.frame, text="Client slots", **STYLES["widget"]).grid(row=row, column=3, columnspan=2)
        row += 1

        for flight_task in self.event.tasks:
            header("{}:".format(self.event.flight_name(flight_task)))
            if flight_task == PinpointStrike:
                if not self.base.armor:
                    label("No units")
                for t, c in self.base.armor.items():
                    scrable_row(flight_task, t, c, client_slots=False)
            else:
                if not self.base.aircraft:
                    label("No units")
                for t, c in self.base.aircraft.items():
                    scrable_row(flight_task, t, c, client_slots=True)

        header("Support:")
        # Options
        awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED
        Label(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), **STYLES["widget"]).grid(row=row, column=0, sticky=W, pady=5)
        Checkbutton(self.frame, var=self.awacs, state=awacs_enabled,  **STYLES["radiobutton"]).grid(row=row, column=4, sticky=E)
        row += 1

        Label(self.frame, text="Combined Arms Slots", **STYLES["widget"]).grid(row=row, sticky=W)
        self.ca_slot_entry = Entry(self.frame,  width=2)
        self.ca_slot_entry.insert(0, "0")
        self.ca_slot_entry.grid(column=3, row=row, sticky=E, padx=5)
        Button(self.frame, text="+", command=self.add_ca_slot, **STYLES["btn-primary"]).grid(column=4, row=row, padx=5, sticky=W)
        row += 1

        header("Ready?")
        self.error_label = label("", columnspan=4)
        self.error_label["fg"] = RED
        Button(self.frame, text="Commit", command=self.start, **STYLES["btn-primary"]).grid(column=0, row=row, sticky=E, padx=5, pady=(10,10))
        Button(self.frame, text="Back", command=self.dismiss, **STYLES["btn-warning"]).grid(column=3, row=row, sticky=E, padx=5, pady=(10,10))
        row += 1

    def scramble_half(self, task: typing.Type[UnitType], unit_type: UnitType) -> typing.Callable:
        def action():
            entry = self.scramble_entries[task][unit_type][0]  # type: Entry
            value = entry.get()

            total_units = self.base.total_units_of_type(unit_type)

            amount = int(value and value or "0")
            entry.delete(0, END)
            entry.insert(0, str(amount + int(math.ceil(total_units/2))))

        return action

    def add_ca_slot(self):
        value = self.ca_slot_entry.get()
        amount = int(value and value or "0")
        self.ca_slot_entry.delete(0, END)
        self.ca_slot_entry.insert(0, str(amount+1))

    def client_one(self, task: typing.Type[Task], unit_type: UnitType) -> typing.Callable:
        def action():
            entry = self.scramble_entries[task][unit_type][1]  # type: Entry
            value = entry.get()
            amount = int(value and value or "0")
            entry.delete(0, END)
            entry.insert(0, str(amount+1))
        return action

    def start(self):
        if self.awacs.get() == 1:
            self.event.is_awacs_enabled = True
            self.game.awacs_expense_commit()
        else:
            self.event.is_awacs_enabled = False

        ca_slot_entry_value = self.ca_slot_entry.get()
        try:
            ca_slots = int(ca_slot_entry_value and ca_slot_entry_value or "0")
        except:
            ca_slots = 0
        self.event.ca_slots = ca_slots

        flights = {k: {} for k in self.event.tasks}  # type: db.TaskForceDict
        units_scramble_counts = {}  # type: typing.Dict[typing.Type[UnitType], int]
        tasks_scramble_counts = {}  # type: typing.Dict[typing.Type[Task], int]
        tasks_clients_counts = {}  # type: typing.Dict[typing.Type[Task], int]

        def dampen_count(for_task: typing.Type[Task], unit_type: typing.Type[UnitType], count: int) -> int:
            nonlocal units_scramble_counts
            total_count = self.base.total_units_of_type(unit_type)

            total_scrambled = units_scramble_counts.get(unit_type, 0)
            dampened_value = count if count + total_scrambled < total_count else total_count - total_scrambled
            units_scramble_counts[unit_type] = units_scramble_counts.get(unit_type, 0) + dampened_value

            return dampened_value

        for task_type, dict in self.scramble_entries.items():
            for unit_type, (count_entry, clients_entry) in dict.items():
                try:
                    count = int(count_entry.get())
                except:
                    count = 0

                try:
                    clients_count = int(clients_entry and clients_entry.get() or 0)
                except:
                    clients_count = 0

                dampened_count = dampen_count(task_type, unit_type, count)
                tasks_clients_counts[task_type] = tasks_clients_counts.get(task_type, 0) + clients_count
                tasks_scramble_counts[task_type] = tasks_scramble_counts.get(task_type, 0) + dampened_count

                flights[task_type][unit_type] = dampened_count, clients_count

        for task in self.event.ai_banned_tasks:
            if tasks_clients_counts.get(task, 0) == 0 and tasks_scramble_counts.get(task, 0) > 0:
                self.error_label["text"] = "Need at least one player in flight {}".format(self.event.flight_name(task))
                return

        for task in self.event.player_banned_tasks:
            if tasks_clients_counts.get(task, 0) != 0:
                self.error_label["text"] = "Players are not allowed on flight {}".format(self.event.flight_name(task))
                return

        if self.game.is_player_attack(self.event):
            if isinstance(self.event, FrontlineAttackEvent) or isinstance(self.event, FrontlinePatrolEvent):
                if self.event.from_cp.base.total_armor == 0:
                    self.error_label["text"] = "No ground vehicles available to attack!"
                    return

            self.event.player_attacking(flights)
        else:
            if isinstance(self.event, FrontlineAttackEvent) or isinstance(self.event, FrontlinePatrolEvent):
                if self.event.to_cp.base.total_armor == 0:
                    self.error_label["text"] = "No ground vehicles available to defend!"
                    return

            self.event.player_defending(flights)

        self.game.initiate_event(self.event)
        EventResultsMenu(self.window, self.parent, self.game, self.event).display()

