import Sequence
import os
import Actor
import Entity
import Effect
import CellMark
from Log import LOG
from Gui import GUI
from Reader import reader

seq = {
    1: "spell_sequence",
    2: "melee_sequence",
    5: "move_sequence"
}

class Combat():
    def __init__(self):
        self.combat_parse = -1 # -1: NONE, 0: PARTIAL, 1: FULL
        self.entities = {}
        self.playing_entity = None
        self.find_playing_entity = False
        self.latest_id = -1.0
        self.current_round = -1
        self.dying_entity = None
        self.spectating = False

    def combat_start(self):
        return self

    def show_fighters(self):
        return

    def combat_spectate_init(self):
        effects_len = reader.readUnsignedShort()
        effects = []
        for _ in range(0, effects_len):
            effects.append(Effect.CombatEffect())
        marks_len = reader.readUnsignedShort()
        marks = []
        for _ in range(0, marks_len):
            marks.append(CellMark.CellMark())
        for eff in effects:
            effect = eff.effect
            self.entities[effect.target_id].add_effect(effect)
        self.find_playing_entity = True
        for _, e in self.entities.items():
            e.determine_base_papm()

    def set_sequence(self, sequence):
        if self.find_playing_entity == True:
            self.find_playing_entity = False
            self.turn_set(sequence.author_id, from_spec=True)


    def GameFightSynchronize(self):
        length = reader.readUnsignedShort()
        for _ in range(0, length):
            actor = DummyActor()
            typev = reader.readType()
            if typev == "GameFightCharacterInformations;":
                actor.entity = Actor.FightCharacterInformations()
            elif typev == "GameFightMonsterInformations;":
                actor.entity = Actor.FightMonsterInformations()
            elif typev == "GameFightTaxCollectorInformations;":
                actor.entity = Actor.FightTaxCollectorInformations()
            elif typev == "GameFightEntityInformation;":
                actor.entity = Actor.FightEntityInformation()
            elif typev == "GameFightMutantInformations;":
                actor.entity = Actor.FightMutantInformation()
            else:
                LOG.error(f"Unhandled type {typev} for GameFightSynchronize.actor")
            if actor != None:
                e = Entity.Entity()
                e.load_actor(actor)
                self.add_entity(e)

    def add_entity(self, entity, summoned=False):
        if entity.contextual_id <= self.latest_id:
            self.latest_id = entity.contextual_id - 1
        if entity.contextual_id not in self.entities.keys():
            self.entities[entity.contextual_id] = entity
            if summoned == False:
                LOG.info(f"New fighter - {entity.name}")


    def get_latest_id(self):
        LOG.error("Calling to deprecated function get_latest_id")
        self.latest_id -= 1
        return self.latest_id + 1

    def set_playing_entity(self, entity):
        return
        #if entity != None:
        #    if entity not in self.entities:
        #        self.entities[entity] = Entity()
        #    self.playing_entity = self.entities[entity]
        #else:
        #    self.playing_entity = None

    def parse_spell(self, entity):
        if entity.contextual_id not in self.entities:
            self.entities[entity.contextual_id] = entity
        #self.playing_entity = entity
        spell = entity.parse_spell()
        if spell.noise != 2:
            return False
        LOG.info(f"Cast: {spell.spell_name} on {self.entities[spell.target_id].name if int(spell.target_id) != 0 else 'ground'} (CELL: {spell.destination_cell})")
        return True

    def synchronize(self):
        return

    def parse_attack(self, entity):
        if entity.contextual_id not in self.entities:
            self.entities[entity.contextual_id] = entity
        spell = entity.parse_attack()
        if spell.noise != 2:
            return False
        #if spell.target_id not in self.entities:
        #    self.entities[spell.target_id] = Entity()
        LOG.info(f"Cast: {spell.spell_name} on {self.entities[spell.target_id].name if int(spell.target_id) != 0 else 'ground'} (CELL: {spell.destination_cell})")
        return True

    def parse_sequence(self, message):
        _ = Sequence.Sequence(message)
        #if self.playing_entity != None:
        #    self.playing_entity.parse_sequence()

    def new_round(self):
        c_round = reader.readVarUhInt()
        if self.current_round == -1:
            if c_round == 1:
                self.combat_parse = 1
            else:
                self.combat_parse = 0
        self.current_round = c_round
        LOG.info(f"Starting round {self.current_round}")

    def add_effect(self, effect):

        if effect.target_id in self.entities.keys():
            self.entities[effect.target_id].add_effect(effect)
        else:
            LOG.error("Unable to find correct entity")

    def dispell_single_effect(self):
        action_id = reader.readVarUhShort()
        source_id = reader.readDouble()
        target_id = reader.readDouble()
        verbose = reader.readBoolean()
        boost_uid = reader.readInt()
        if target_id in self.entities.keys():
            self.entities[target_id].dispell_single_effect(boost_uid)

    def parse_points_variation(self):
        action_id = reader.readVarUhShort()
        source_id = reader.readDouble()
        target_id = reader.readDouble()
        delta = reader.readShort()
        if target_id in self.entities.keys():
            self.entities[target_id].parse_points_variation(delta, action_id)

    def dispell_effects(self):
        action_id = reader.readVarUhShort()
        source_id = reader.readDouble()
        target_id = reader.readDouble()
        delta = reader.readShort()
        if target_id in self.entities.keys():
            self.entities[target_id].dispell_effects(delta)

    def turn_set(self, id_player, from_spec=False):
        if id_player in self.entities:
            if self.playing_entity is not None:
                self.turn_end()
            self.playing_entity = self.entities[id_player]
            self.playing_entity.is_playing = True
            if from_spec == False:
                self.cycle_entity_effects(self.playing_entity.contextual_id)
            self.playing_entity.compute_effects()
            LOG.info(f"Turn start for {self.playing_entity.name} ({self.playing_entity.current_pa}/{self.playing_entity.current_pm})")

    def turn_end(self, id_player=None):
        if self.playing_entity is None:
            return
        LOG.info(f"Turn end for {self.playing_entity.name}")
        self.playing_entity.is_playing = False
        self.playing_entity.spent_pa = 0
        self.playing_entity.spent_pm = 0
        self.playing_entity = None
        return

    def entity_death(self):
        action_id = reader.readVarUhShort()
        source_id = reader.readDouble()
        target_id = reader.readDouble()
        if target_id in self.entities.keys():
            self.entities[target_id].entity_death()
            self.dying_entity = self.entities[target_id]
        for k, ent in self.entities.items():
            ent.dispell_effects_from_source(target_id)
        self.dying_entity = None

    def cycle_entity_effects(self, uid):
        for k, ent in self.entities.items():
            ent.cycle_effects_from_source(uid)

    def combat_end(self):
        pass

    def combat_report(self):
        combat_ent = {}
        summoned_to_add = []
        total_damage = 0
        for k, ent in self.entities.items():
            if ent.summoner is not None:
                summoned_to_add.append(ent)
            elif ent.is_player == True:
                combat_ent[k] = [ent.name, ent.get_breed(), ent.team, ent.get_damage(), k]
                total_damage += ent.get_damage()
        for summ in summoned_to_add:
            if summ.summoner.contextual_id in combat_ent:
                combat_ent[summ.summoner.contextual_id][3] += summ.get_damage()
        ord_report = sorted(combat_ent.items(), key=lambda x: x[1][3], reverse=True)
        string = ""
        first = ""
        j = 0
        for i in ord_report:
            if first == "":
                first = i
            if i[1][3] > 0:
                string += f"""
                    <div class="overbar" onclick="set_combat_player_view('{i[1][0]}')" id="player_{j}" data-value="{i[1][0]}">
                        <span class="bar {i[1][1]}" style="width:{int((i[1][3] / first[1][3]) * 90)}%;">
                            <div class="namebar"><p class="align-left">{i[1][0]}</p> <p class="align-right">{i[1][3]}</p></div>
                        </span>
                    </div>
                """
            spell_list = {}
            for spell in self.entities[i[1][4]].spells:
                if spell.spell_name not in spell_list:
                    spell_list[spell.spell_name] = []
                    spell_list[spell.spell_name].append(0)
                for dmg in spell.damage:
                    spell_list[spell.spell_name][0] += dmg['loss']
                    if len(spell_list[spell.spell_name]) < 2:
                        spell_list[spell.spell_name].append(dmg['element_id'])
                    elif spell_list[spell.spell_name][1] != dmg['element_id']:
                        spell_list[spell.spell_name][1] = 'multi'
                spell_list['Summons'] = []
                spell_list['Summons'].append(0)
                for summ in self.entities[i[1][4]].summons:
                    spell_list['Summons'][0] += summ.get_damage()
                    spell_list['Summons'].append(summ.get_elem())
            ord_spells = sorted(spell_list.items(), key=lambda x: x[1][0], reverse=True)
            spell_string = ""
            for sp in ord_spells:
                if sp[1][0] == 0:
                    continue
                spell_string += f"""
                <div class="spell_overbar">
                <span class="bar elem-{sp[1][1]}" style="width:{sp[1][0] / ord_spells[0][1][0] * 90}%;">
                <div class="namebar"><p class="align-left">{sp[0]}</p> <p class="align-right">{sp[1][0]}</p></div>
                </span>
                </div>
                """
            if GUI.window != None:
                GUI.update_player_combat_html(i[1][0], spell_string)
            j += 1
        if GUI.window != None:
            GUI.update_combat_html(string)


class DummyActor():
    def __init__(self):
        self.entity = None