from ..List.configDict import locationType
from . import encoding


class ProgressionPoints:
    def __init__(self):
        self.gen_to_tracker_location_map = {
            locationType.Level: "Levels",
            locationType.FormLevel: "Drives",
            locationType.STT: "SimulatedTwilightTown",
            locationType.TT: "TwilightTown",
            locationType.HB: "HollowBastion",
            locationType.BC: "BeastsCastle",
            locationType.OC: "OlympusColiseum",
            locationType.Agrabah: "Agrabah",
            locationType.LoD: "LandofDragons",
            locationType.HUNDREDAW: "HundredAcreWood",
            locationType.PL: "PrideLands",
            locationType.Atlantica: "Atlantica",
            locationType.DC: "DisneyCastle",
            locationType.HT: "HalloweenTown",
            locationType.PR: "PortRoyal",
            locationType.SP: "SpaceParanoids",
            locationType.TWTNW: "TWTNW",
            locationType.CoR: "CavernofRemembrance",
        }
        self.initialize_points()
        self.initialize_point_thresholds()

    def get_world_options(self):
        return list(self.gen_to_tracker_location_map.keys())

    def get_num_cp_for_world(self, world: locationType):
        return len(self.points[world])

    def get_cp_for_world(self, world: locationType, index: int):
        return self.points[world][index]

    def get_cp_label_for_world(self, world: locationType, index: int):
        human_readable_labels = {
            "Levels": ["Level 10", "Level 20", "Level 30", "Level 40", "Level 50"],
            "Drives": [
                "Drive Level 2",
                "Drive Level 3",
                "Drive Level 4",
                "Drive Level 5",
                "Drive Level 6",
                "Drive Level 7",
            ],
            "SimulatedTwilightTown": [
                "STT Enter",
                "Olette Munny Pouch",
                "Twilight Thorn",
                "Axel 1",
                "Setzer",
                "Mansion Computer Room",
                "Axel 2",
                "Data Roxas",
            ],
            "TwilightTown": [
                "Twilight Town Enter",
                "Station Dusk Fight",
                "Mysterious Tower",
                "Sandlot Fight",
                "Mansion Fight",
                "Betwixt and Between",
                "Data Axel",
            ],
            "HollowBastion": [
                "Hollow Bastion Enter",
                "Bailey Fight",
                "Ansem's Study Computer",
                "Corridors Fight",
                "Dancers Fight",
                "Demyx",
                "Final Fantasy Fights",
                "1000 Heartless",
                "Sephiroth",
                "Data Demyx",
            ],
            "LandofDragons": [
                "Land of Dragons Enter",
                "Mission 3",
                "Mountain Trail",
                "Cave Fight",
                "Summit Fight",
                "Shan Yu",
                "Antechamber Nobodies",
                "Stormrider",
                "Data Xigbar",
            ],
            "BeastsCastle": [
                "Beast's Castle Enter",
                "Thresholder",
                "Beast's Room",
                "Dark Thorn",
                "Ballroom Dragoons Fight",
                "Xaldin",
                "Data Xaldin",
            ],
            "OlympusColiseum": [
                "Olympus Coliseum Enter",
                "Cerberus",
                "Phil's Urns",
                "Demyx",
                "Pete",
                "Hydra",
                "Auron Statue",
                "Hades",
                "AS Zexion",
                "Data Zexion",
            ],
            "DisneyCastle": [
                "Disney Castle Enter",
                "Minnie Escort",
                "Old Pete",
                "Timeless River Windows",
                "Boat Pete",
                "Pete",
                "AS Marluxia",
                "Data Marluxia",
                "Lingering Will",
            ],
            "PortRoyal": [
                "Port Royal Enter",
                "Town Fight",
                "1 Minute Fight",
                "Boat Medallion",
                "Boat Barrels",
                "Barbossa",
                "Grim Reaper 1",
                "First Medallion Gambler",
                "Grim Reaper 2",
                "Data Luxord",
            ],
            "Agrabah": [
                "Agrabah Enter",
                "Abu Minigame",
                "Chasm of Challenges",
                "Treasure Room",
                "Twin Lords",
                "Carpet Magic",
                "Genie Jafar",
                "AS Lexaeus",
                "Data Lexaeus",
            ],
            "HalloweenTown": [
                "Halloween Town Enter",
                "Candy Cane Lane Fight",
                "Prison Keeper",
                "Oogie Boogie",
                "Lock, Shock, Barrel",
                "Presents Minigame",
                "Experiment",
                "AS Vexen",
                "Data Vexen",
            ],
            "PrideLands": [
                "Pride Lands Enter",
                "Talking to Simba",
                "Hyenas 1",
                "Scar",
                "Hyenas 2",
                "Groundshaker",
                "Data Saix",
            ],
            "SpaceParanoids": [
                "Space Paranoids Enter",
                "Screens",
                "Hostile Program",
                "Solar Sailer Fight",
                "MCP",
                "AS Larxene",
                "Data Larxene",
            ],
            "HundredAcreWood": [
                "Pooh's Howse Enter",
                "Piglet's Howse Complete",
                "Rabbit's Howse Complete",
                "Kanga's Howse Complete",
                "Spooky Cave Complete",
                "Starry Hill Complete",
            ],
            "Atlantica": [
                "Atlantica Enter",
                "Ursula's Revenge",
                "A New Day is Dawning",
            ],
            "TWTNW": [
                "TWTNW Enter",
                "Roxas",
                "Xigbar",
                "Luxord",
                "Saix",
                "Xemnas 1",
                "Data Xemnas",
            ],
            "CavernofRemembrance": [
                "CoR Enter",
                "First Fight",
                "Steam Valves",
                "Second Fight",
                "Transport to Remembrance",
            ],
        }
        return human_readable_labels[self.gen_to_tracker_location_map[world]][index]

    def set_cp_for_world(self, world: locationType, index: int, value: int):
        self.points[world][index] = value

    def initialize_point_thresholds(self):
        self.point_thresholds = [
            3,
            3,
            3,
            4,
            4,
            4,
            5,
            5,
            5,
            6,
            6,
            6,
            7,
            7,
            7,
            8,
            8,
            8,
        ]  # max 18 (17 worlds + creations)

    def initialize_points(self):
        self.points = {
            locationType.Level: [0, 0, 1, 1, 2],
            locationType.FormLevel: [0, 0, 0, 1, 1, 1],
            locationType.STT: [0, 1, 2, 1, 1, 1, 1, 6],
            locationType.TT: [0, 1, 1, 2, 2, 2, 6],
            locationType.HB: [0, 1, 0, 2, 1, 2, 2, 2, 5, 6],
            locationType.BC: [0, 2, 1, 2, 1, 3, 6],
            locationType.OC: [0, 2, 0, 2, 0, 2, 2, 3, 3, 6],
            locationType.Agrabah: [0, 1, 1, 1, 2, 1, 3, 4, 6],
            locationType.LoD: [0, 1, 1, 1, 1, 2, 0, 3, 6],
            locationType.HUNDREDAW: [0, 1, 1, 1, 2, 4],
            locationType.PL: [0, 1, 1, 2, 1, 3, 6],
            locationType.Atlantica: [0, 5, 3],
            locationType.DC: [0, 1, 1, 2, 1, 2, 5, 6, 7],
            locationType.HT: [0, 1, 2, 2, 1, 1, 3, 3, 6],
            locationType.PR: [0, 1, 1, 0, 1, 2, 1, 1, 3, 6],
            locationType.SP: [0, 1, 2, 2, 2, 4, 6],
            locationType.TWTNW: [0, 2, 3, 2, 2, 2, 7],
            locationType.CoR: [0, 4, 0, 4, 7],
        }

    def get_compressed(self) -> str:
        keys = list(self.points.keys())

        threshold_characters = ""
        for p in self.point_thresholds:
            threshold_characters += str(p)

        points_characters = ""
        for k in keys:
            for i in range(len(self.points[k])):
                points_characters += str(self.points[k][i])

        threshold_result = encoding.v2r(int(threshold_characters))
        points_result = encoding.v2r(int(points_characters))
        result = threshold_result + "+" + points_result

        return result

    def set_uncompressed(self, compressed_string: str):
        keys = list(self.points.keys())

        split_strings = compressed_string.split("+")

        threshold_count = len(self.point_thresholds)
        decoded_threshold = str(encoding.r2v(split_strings[0]))
        threshold_characters = self._prepend_zeroes(
            decoded_threshold, expected_length=threshold_count
        )
        for i in range(threshold_count):
            self.set_point_threshold(i, int(threshold_characters[i]))

        points_expected_length = 0
        for k in keys:
            points_expected_length = points_expected_length + len(self.points[k])
        decoded_points = str(encoding.r2v(split_strings[1]))
        points_characters = self._prepend_zeroes(
            decoded_points, expected_length=points_expected_length
        )

        current_index = 0
        for k in keys:
            location_points: list[int] = self.points[k]
            for i in range(len(location_points)):
                location_points[i] = int(points_characters[current_index])
                current_index += 1

        return True

    def get_point_threshold(self, index):
        return self.point_thresholds[index]

    def set_point_threshold(self, index, value):
        self.point_thresholds[index] = value

    def get_hint_thresholds(self, world_count):
        output = [
            self.point_thresholds[x]
            for x in range(len(self.point_thresholds))
            if x < world_count
        ]
        return output

    def get_points_json(self):
        output = {}
        for l in locationType:
            if l in self.points:
                output[self.gen_to_tracker_location_map[l]] = self.points[l]
        return output

    def settings_spoiler_json(self) -> dict[str, list[int]]:
        output = {"Hint Thresholds": self.point_thresholds}
        for location in locationType:
            if location in self.points:
                output[locationType(location).value] = self.points[location]
        return output

    @staticmethod
    def _prepend_zeroes(value: str, expected_length: int) -> str:
        difference = expected_length - len(value)
        return ("0" * difference) + value
