from Reader import reader, types, status
from Log import LOG
from Gui import GUI
import Map
import requests
from map_hints import hints
import os
import math
from Options import options
import json
from i18n import i18n_fr
from pickler import decompress_pickle
from Server import server


class TreasureHints():
    def __init__(self):
        self.data = decompress_pickle(f'{os.path.dirname(__file__)}/data/PointOfInterest.pbz2')

treasure_hints = TreasureHints()
class TreasureHuntStep():
    def __init__(self):
        return

class TreasureHuntStepFight():
    def __init__(self):
        self.type = "TreasureHuntStepFight"
        return
    def dump(self):
        return

class TreasureHuntStepDig():
    def __init__(self):
        return

class TreasureHuntStepFollowDirection():
    def __init__(self):
        self.type = "TreasureHuntStepFollowDirection"
        self.direction = reader.readByte()
        self.map_count = reader.readVarUhShort()

    def dump(self):
        LOG.info(f"Direction: {self.direction}")
        LOG.info(f"Map count: {self.map_count}")
        return
#Classic hunt value
class TreasureHuntStepFollowDirectionToHint():
    def __init__(self):
        self.type = "TreasureHuntStepFollowDirectionToHint"
        self.direction = reader.readByte()
        self.npc_id = reader.readVarUhShort()

    def dump(self):
        LOG.info(f"Direction: {self.direction}")
        LOG.info(f"NPC ID: {self.npc_id}")
        return

class TreasureHuntStepFollowDirectionToPOI():
    def __init__(self):
        self.type = "TreasureHuntStepFollowDirectionToPOI"
        self.direction = reader.readByte()
        self.poi_id = reader.readVarUhShort()

    def dump(self):
        LOG.info(f"Direction: {self.direction}")
        LOG.info(f"Point of Interest ID: {self.poi_id}")
        return

class TreasureHuntFlag():
    def __init__(self):
        self.map_id = reader.readDouble()
        self.state = reader.readByte()
        return

class Hint():
    def __init__(self):
        self.current_type = None
        self.maps_run = 0
        return

    def solve_step(self):
        if self.flags_len == self.total_steps:
            return "ok"
        self.looking_for_npc = None
        step = self.steps[-1]
        if len(self.flags) > 0:
            map_x, map_y, _ = Map.get_coords(self.flags[-1].map_id)
        else:
            map_x, map_y, _ = Map.get_coords(self.map)
        self.current_type = step.type
        if step.type == "TreasureHuntStepFollowDirectionToPOI":
            data_dm_id = -1
            for data in treasure_hints.data:
                if int(data['id']) == int(step.poi_id):
                    data_val = (i18n_fr.get_name(str(data['nameId'])))
                    for k,v in hints.items():
                        if v.lower() == data_val.lower():
                            data_dm_id = int(k)
            if data_dm_id == -1:
                LOG.error("Hint not found")
                return -1
            string = f"https://dofus-map.com/huntTool/getData.php?x={map_x}&y={map_y}&direction={self.d_value[step.direction]}&world=0&language=fr"
            ret = requests.get(string).json()
            for i in ret['hints']:
                if int(i['n']) == int(data_dm_id):
                    self.current_type = "TreasureHuntStepFollowDirectionToPOI"
                    self.going_to_x = int(i['x'])
                    self.going_to_y = int(i['y'])
                    self.direction = self.d_value[step.direction]
                    self.nb_maps = int(i['d'])
                    self.maps_run += self.nb_maps
                    LOG.info(f"located {i['d']} maps away ([{i['x']}, {i['y']}])")
                    LOG.info(f"/travel {self.going_to_x} {self.going_to_y}")
                    self.error = False
                    return
            self.current_type = "ERROR"
        elif step.type == "TreasureHuntStepFight":
            self.current_type = "TreasureHuntStepFight"
            #print("Hunt finished")
        elif step.type == "TreasureHuntStepFollowDirectionToHint":
            self.looking_for_npc = int(step.npc_id)
            self.current_type = "TreasureHuntStepFollowDirectionToHint"
            self.direction = self.d_value[step.direction]

    def parse_message(self):
        self.type = reader.readByte()
        self.map = reader.readDouble()
        self.looking_for_npc = None
        self.x, self.y, _ = Map.get_coords(self.map)
        self.d_value = {
            0: "right",
            2: "bottom",
            4: "left",
            6: "top"
        }
        self.previous_steps_len = reader.readUnsignedShort()
        self.steps = []
        for i in range(0, self.previous_steps_len):
            typev = reader.readType()
            if typev == "TreasureHuntStep;":
                self.steps.append(TreasureHuntStep())
            elif typev == "TreasureHuntStepFollowDirectionToPOI;":
                self.steps.append(TreasureHuntStepFollowDirectionToPOI())
            elif typev == "TreasureHuntStepDig;":
                self.steps.append(TreasureHuntStepDig())
            elif typev == "TreasureHuntStepFight;":
                self.steps.append(TreasureHuntStepFight())
            elif typev == "TreasureHuntStepFollowDirectionToHint;":
                self.steps.append(TreasureHuntStepFollowDirectionToHint())
            elif typev == "TreasureHuntStepFollowDirection;":
                self.steps.append(TreasureHuntStepFollowDirection())
            else:
                LOG.error(f"Unhandled type {typev} for TreasureHuntStep")
        self.total_steps = reader.readByte()
        self.current_point = reader.readVarUhInt()
        self.total_points = reader.readVarUhInt()
        self.retries = reader.readInt()
        self.flags_len = reader.readUnsignedShort()
        self.flags = []
        for i in range(0, self.flags_len):
            self.flags.append(TreasureHuntFlag())
        return

    def to_html(self, _map, ok=0, end=False):
        if end == True:
            GUI.hunt_html = f"""
                <div class="hunt_container">
                    <div class="arrowhunt_container">
                        <span class="checkmark">
                            <div class="checkmark_stem"></div>
                            <div class="checkmark_kick"></div>
                        </span>
                    </div>
                    <div class="infohunt_container">
                        Hunt finished on {_map.x}{_map.y}
                    </div>
                </div>
            """
        if ok == 1:
            GUI.hunt_html = """
                <div class="hunt_container">
                    <div class="arrowhunt_container">
                        <span class="checkmark">
                            <div class="checkmark_stem"></div>
                            <div class="checkmark_kick"></div>
                        </span>
                    </div>
                    <div class="infohunt_container">
                        On correct map
                    </div>
                </div>
                """
            GUI.send_body()
            return
        if self.current_type == "ERROR":
            GUI.hunt_html = """
                <div class="hunt_container">
                    <div class="arrowhunt_container">
                    </div>
                    <div class="infohunt_container">
                        An error occured.
                </div>
                """
        elif self.current_type == "TreasureHuntStepFollowDirectionToPOI":
            if _map.x == None or _map.y == None:
                GUI.hunt_html = f"""
                    <div class="hunt_container">
                        <div class="arrowhunt_container">
                            <div class="arrowhunt arrowhunt--{self.direction}">
                            </div>
                        </div>
                        <div class="infohunt_container">
                            {self.nb_maps} maps<br />
                            [{self.going_to_x}, {self.going_to_y}]
                            <br />
                            <input type="text" class="fm_pool_input" value="/travel {self.going_to_x} {self.going_to_y}" id="fm_pool_current_value">

                    </div>
                """
            elif _map.x != self.going_to_x:
                if _map.x < self.going_to_x:
                    direction = "right"
                else:
                    direction = "left"
                val = int(math.sqrt((_map.x - self.going_to_x) * (_map.x - self.going_to_x)))
                GUI.hunt_html = f"""
                    <div class="hunt_container">
                        <div class="arrowhunt_container">
                            <div class="arrowhunt arrowhunt--{direction}">
                            </div>
                        </div>
                        <div class="infohunt_container">
                            {val} maps<br />
                            [{self.going_to_x}, {self.going_to_y}]
                            <br />
                            <input type="text" class="fm_pool_input" value="/travel {self.going_to_x} {self.going_to_y}" id="fm_pool_current_value">
                    </div>
                """
            elif _map.y != self.going_to_y:
                if _map.y > self.going_to_y:
                    direction = "top"
                else:
                    direction = "bottom"
                val = int(math.sqrt((_map.y - self.going_to_y) * (_map.y - self.going_to_y)))
                GUI.hunt_html = f"""
                <div class="hunt_container">
                    <div class="arrowhunt_container">
                        <div class="arrowhunt arrowhunt--{direction}">
                        </div>
                    </div>
                    <div class="infohunt_container">
                        {val} maps<br />
                        [{self.going_to_x}, {self.going_to_y}] <br />
                        <input type="text" class="fm_pool_input" value="/travel {self.going_to_x} {self.going_to_y}" id="fm_pool_current_value">
                </div>
                """
            else:
                GUI.hunt_html = """
        <div class="hunt_container">
            <div class="arrowhunt_container">
                <span class="checkmark">
                    <div class="checkmark_stem"></div>
                    <div class="checkmark_kick"></div>
                </span>
            </div>
            <div class="infohunt_container">
                On correct map
            </div>
        </div>
        """
        elif self.current_type == "TreasureHuntStepFollowDirectionToHint":
            GUI.hunt_html = f"""
                <div class="hunt_container">
                    <div class="arrowhunt_container">
                        <div class="arrowhunt arrowhunt--{self.direction}">
                        </div>
                    </div>
                    <div class="infohunt_container">
                    Looking for the hint. Stay tuned.
                </div>
                """
            if self.looking_for_npc == -1:
                GUI.hunt_html = """
                        <div class="hunt_container">
                            <div class="arrowhunt_container">
                                <span class="checkmark">
                                    <div class="checkmark_stem"></div>
                                    <div class="checkmark_kick"></div>
                                </span>
                            </div>
                            <div class="infohunt_container">
                                On correct map
                            </div>
                        </div>
                        """
        else:
            GUI.hunt_html = """
            <div class="hunt_container">
                No hint to show
            </div>
            """
        GUI.send_body()

    def show_values(self):
        print (f"Hunt type: {self.type}")
        print (f"Map ID: {self.map}")
        print (f"previous steps: {self.previous_steps_len}")
        for i in self.steps:
            print (f"type: {i.type}")
            i.dump()
        print (f"Total steps: {self.total_steps}")
        print (f"Current point(s?): {self.current_point}")
        print (f"Total point: {self.total_points}")
        print (f"Retries: {self.retries}")
        print (f"Nb flags: {self.flags_len}")
        print ("Flags:")
        for i in self.flags:
            print ("- ", end="")
            print (f"Map_id: {i.map_id}, state: {i.state}")
        return
