# vim: set fileencoding=utf-8
import math
import random
from typing import Any, Dict, List, Tuple

from bemani.backend.popn.base import PopnMusicBase
from bemani.backend.popn.common import PopnMusicModernBase
from bemani.backend.popn.peace import PopnMusicPeace
from bemani.common import VersionConstants
from bemani.common.validateddict import Profile
from bemani.data.types import UserID
from bemani.protocol.node import Node


class PopnMusicKaimei(PopnMusicModernBase):

    name: str = "Pop'n Music 解明リドルズ"
    version: int = VersionConstants.POPN_MUSIC_KAIMEI_RIDDLES

    # Biggest ID in the music DB
    GAME_MAX_MUSIC_ID: int = 2019

    # Biggest deco part ID in the game
    GAME_MAX_DECO_ID: int = 133

    # Item limits are as follows:
    # 0: 2019 - ID is the music ID that the player purchased/unlocked.
    # 1: 2344
    # 2: 3
    # 3: 133 - ID points at a character part that can be purchased on the character screen.
    # 4: 1
    # 5: 1
    # 6: 60

    def previous_version(self) -> PopnMusicBase:
        return PopnMusicPeace(self.data, self.config, self.model)

    @classmethod
    def get_settings(cls) -> Dict[str, Any]:
        """
        Return all of our front-end modifiably settings.
        """
        return {
            "ints": [
                {
                    "name": "Music Open Phase",
                    "tip": "Default music phase for all players.",
                    "category": "game_config",
                    "setting": "music_phase",
                    "values": {
                        # The value goes to 30 now, but it starts where usaneko left off at 23
                        # Unlocks a total of 10 songs
                        23: "No music unlocks",
                        24: "Phase 1",
                        25: "Phase 2",
                        26: "Phase 3",
                        27: "Phase 4",
                        28: "Phase 5",
                        29: "Phase 6",
                        30: "Phase MAX",
                    },
                },
                {
                    "name": "Kaimei! MN tanteisha event Phase",
                    "tip": "Kaimei! MN tanteisha event phase for all players.",
                    "category": "game_config",
                    "setting": "mn_tanteisha_phase",
                    "values": {
                        0: "Disabled",
                        1: "Roki",
                        2: "shiroro",
                        3: "PIERRE&JILL",
                        4: "ROSA",
                        5: "taoxiang",
                        6: "TangTang",
                        7: "OTOBEAR",
                        8: "kaorin",
                        9: "CHARLY",
                        10: "ALOE",
                        11: "RIE♥chan",
                        12: "hina",
                        13: "PAPYRUS",
                        14: "雷蔵, miho, RIE♥chan, Ryusei Honey",
                        15: "Murasaki",
                        16: "Lucifelle",
                        17: "六",
                        18: "stella",
                        19: "ちせ",
                        20: "LISA",
                        21: "SUMIRE",
                        22: "SHISHITUGU",
                        23: "WALKER",
                        24: "Candy",
                        25: "Jade",
                        26: "AYA",
                        27: "kaorin",
                        28: "Lord Meh",
                        29: "HAMANOV",
                        30: "Agent",
                        31: "Yima",
                        32: "ikkei",
                        33: "echidna",
                        34: "lithos",
                        35: "SMOKE",
                        36: "the KING",
                        37: "Kicoro",
                        38: "DEBORAH",
                        39: "Teruo",
                        40: "the TOWER",
                        41: "Mamoru-kun",
                        42: "Canopus",
                        43: "Mimi Nyami",
                        44: "iO-LOWER",
                        45: "BOY",
                        46: "Sergei",
                        47: "SAPPHIRE",
                        48: "Chocky",
                        49: "HAPPPY",
                        50: "SHOLLKEE",
                        51: "CHARA-O",
                        52: "Hugh, GRIM, SUMIKO",
                        53: "Peetan",
                        54: "SHARK",
                        55: "Nakajima-san",
                        56: "KIKYO",
                        57: "SUMIRE",
                        58: "NAKAJI",
                        59: "moi moi",
                        60: "TITICACA",
                        61: "MASAMUNE",
                        62: "YUMMY",
                    },
                },
                {
                    # For festive times, it's possible to change the welcome greeting.  I'm not sure why you would want to change this, but now you can.
                    "name": "Holiday Greeting",
                    "tip": "Changes the payment selection confirmation sound.",
                    "category": "game_config",
                    "setting": "holiday_greeting",
                    "values": {
                        0: "Okay!",
                        1: "Merry Christmas!",
                        2: "Happy New Year!",
                    },
                },
                {
                    # peace soundtrack hatsubai kinen SP event, 0 = off, 1 = active, 2 = off (0-2)
                    "name": "peace soundtrack hatsubai kinen SP",
                    "tip": "peace soundtrack hatsubai kinen SP for all players.",
                    "category": "game_config",
                    "setting": "peace_soundtrack",
                    "values": {
                        0: "Not stated",
                        1: "Active",
                        2: "Ended",
                    },
                },
                {
                    "name": "MZD no kimagure tanteisha joshu",
                    "tip": "Boost increasing the Clarification Level, if four or more Requests still unresolved.",
                    "category": "game_config",
                    "setting": "tanteisha_joshu",
                    "values": {
                        0: "Not stated",
                        1: "Active",
                        2: "Ended",
                    },
                },
                {
                    # Shutchou! pop'n quest Lively II event
                    "name": "Shutchou! pop'n quest Lively phase",
                    "tip": "Shutchou! pop'n quest Lively phase for all players.",
                    "category": "game_config",
                    "setting": "popn_quest_lively",
                    "values": {
                        0: "Not started",
                        1: "fes 1",
                        2: "fes 2",
                        3: "fes FINAL",
                        4: "fes EXTRA",
                        5: "Ended",
                    },
                },
                {
                    # Shutchou! pop'n quest Lively II event
                    "name": "Shutchou! pop'n quest Lively II phase",
                    "tip": "Shutchou! pop'n quest Lively II phase for all players.",
                    "category": "game_config",
                    "setting": "popn_quest_lively_2",
                    "values": {
                        0: "Not started",
                        1: "fes 1",
                        2: "fes 2",
                        3: "fes FINAL",
                        4: "fes EXTRA",
                        5: "fes THE END",
                        6: "Ended",
                    },
                },
            ],
            "bools": [
                # We don't currently support lobbies or anything, so this is commented out until
                # somebody gets around to implementing it.
                # {
                #     'name': 'Net Taisen',
                #     'tip': 'Enable Net Taisen, including win/loss display on song select',
                #     'category': 'game_config',
                #     'setting': 'enable_net_taisen',
                # },
                {
                    "name": "Force Song Unlock",
                    "tip": "Force unlock all songs.",
                    "category": "game_config",
                    "setting": "force_unlock_songs",
                },
            ],
        }

    def get_common_config(self) -> Tuple[Dict[int, int], bool]:
        game_config = self.get_game_config()
        music_phase = game_config.get_int("music_phase")
        holiday_greeting = game_config.get_int("holiday_greeting")
        enable_net_taisen = False  # game_config.get_bool('enable_net_taisen')
        mn_tanteisha_phase = game_config.get_int("mn_tanteisha_phase")
        peace_soundtrack = game_config.get_int("peace_soundtrack")
        tanteisha_joshu = game_config.get_int("tanteisha_joshu")
        popn_quest_lively = game_config.get_int("popn_quest_lively")
        popn_quest_lively_2 = game_config.get_int("popn_quest_lively_2")

        # Event phases
        return (
            {
                # Default song phase availability (0-30)
                # The following songs are unlocked when the phase is at or above the number specified:
                # For 23 and before, see usaneko/peace
                # 24 - 1929, 1930
                # 25 - 1964
                # 26 - 1966, 1967
                # 27 - 1975
                # 28 - 1994
                # 29 - 1995, 1996
                # 30 - 1997
                0: music_phase,
                # Unknown event (0-4)
                1: 4,
                # Holiday Greeting (0-2)
                2: holiday_greeting,
                # Unknown event (0-4)
                3: 4,
                # Unknown event (0-1)
                4: 1,
                # Enable Net Taisen, including win/loss display on song select (0-1)
                5: 1 if enable_net_taisen else 0,
                # Enable NAVI-kun shunkyoku toujou, allows song 1608 to be unlocked (0-1)
                6: 1,
                # Unknown event (0-1)
                7: 1,
                # Unknown event (0-2)
                8: 2,
                # Daily Mission (0-2)
                9: 2,
                # NAVI-kun Song phase availability (0-30)
                10: 30,
                # Unknown event (0-1)
                11: 1,
                # Unknown event (0-2)
                12: 2,
                # Enable Pop'n Peace preview song (0-1)
                13: 1,
                # Stamp Card Rally (0-39)
                14: 39,
                # Unknown event (0-2)
                15: 2,
                # Unknown event (0-3)
                16: 3,
                # Unknown event (0-8)
                17: 8,
                # FLOOR INFECTION event (0-1)
                18: 1,
                # pop'n music × NOSTALGIA kyouenkai (0-1)
                19: 1,
                # Event archive event (0-13)
                20: 13,
                # Pop'n event archive song phase availability (0-20)
                21: 20,
                # バンめし♪ ふるさとグランプリunlocks (split into two rounds) (0-2)
                22: 2,
                # いちかのBEMANI投票選抜戦2019 unlocks (0-1)
                23: 1,
                # ダンキラ!!! × pop'n music unlocks (0-1)
                24: 1,
                # Kaimei riddles events starts here
                # Kaimei! MN tanteisha event Phase (0-62)
                # When active, the following songs are available for unlock
                # 1: 1914
                # 2: 195
                # 3: 1915
                # 4: 1916
                # 5: 1896
                # 6: 1908
                # 7: 1931
                # 8: 1924
                # 9: 1925
                # 10: 1894
                # 11: 1926
                # 12: 1927
                # 13: 1928
                # 14: 1932, 1933, 1934, 1935
                # 15: 521
                # 16: 1936
                # 17: 1943
                # 18: 1937
                # 19: 1938
                # 20: 1939
                # 21: 1943
                # 22: 1941
                # 23: 1942
                # 24: 323
                # 25: 1946
                # 26: 575
                # 27: 1947
                # 28: 1955
                # 29: 1957
                # 30: 1958
                # 31: 1959
                # 32: 1960
                # 33: 1961
                # 34: 1963
                # 35: 1962
                # 36: 1968
                # 37: 1969
                # 38: 1965
                # 39: 1970
                # 40: 1976
                # 41: 1977
                # 42: 1978
                # 43: 1945
                # 44: 1944
                # 45: 1999
                # 46: 2000
                # 47: 2001
                # 48: 2002
                # 49: 2003
                # 50: 2004
                # 51: 2005
                # 52: 267, 1998, 2006
                # 53: 2011
                # 54: 2007
                # 55: 2008
                # 56: 2009
                # 57: 2010
                # 58: 2016
                # 59: 2012
                # 60: 2018
                # 61: 2013
                # 62: 2015
                25: mn_tanteisha_phase,
                # Unknown event (0-3)
                26: 3,
                # peace soundtrack hatsubai kinen SP (0-2)
                # When active, the following songs are available for unlock: 1971, 1972, 1973
                27: peace_soundtrack,
                # MZD no kimagure tanteisha joshu (0-2)
                28: tanteisha_joshu,
                # Shutchou! pop'n quest Lively (0-5)
                # When active, the following songs are available for unlock
                # 1: 1917, 1918
                # 2: 1919, 1921
                # 3: 1920, 1922, 1923
                # 4: 1974
                29: popn_quest_lively,
                # Shutchou! pop'n quest Lively II (0-6)
                # When active, the following songs are available for unlock
                # 1: 1989, 1990, 1991
                # 2: 1984, 1985, 1992
                # 3: 1982, 1983, 1988
                # 4: 1986, 1987, 1993
                # 5: 2017
                30: popn_quest_lively_2,
            },
            False,
        )

    def format_profile(self, userid: UserID, profile: Profile) -> Node:
        root = super().format_profile(userid, profile)

        account = root.child("account")
        account.add_child(
            Node.s16("card_again_count", profile.get_int("card_again_count"))
        )
        account.add_child(Node.s16("sp_riddles_id", profile.get_int("sp_riddles_id")))

        # Kaimei riddles events
        event2021 = Node.void("event2021")
        root.add_child(event2021)
        event2021.add_child(Node.u32("point", profile.get_int("point")))
        event2021.add_child(Node.u8("step", profile.get_int("step")))
        event2021.add_child(
            Node.u32_array(
                "quest_point", profile.get_int_array("quest_point", 8, [0] * 8)
            )
        )
        event2021.add_child(Node.u8("step_nos", profile.get_int("step_nos")))
        event2021.add_child(
            Node.u32_array(
                "quest_point_nos",
                profile.get_int_array("quest_point_nos", 13, [0] * 13),
            )
        )

        riddles_data = Node.void("riddles_data")
        root.add_child(riddles_data)

        # Generate Short Riddles for MN tanteisha
        randomRiddles: List[int] = []
        for _ in range(3):
            riddle = 0
            while True:
                riddle = math.floor(random.randrange(1, 21, 1))
                try:
                    randomRiddles.index(riddle)
                except ValueError:
                    break

            randomRiddles.append(riddle)

            sh_riddles = Node.void("sh_riddles")
            riddles_data.add_child(sh_riddles)
            sh_riddles.add_child(Node.u32("sh_riddles_id", riddle))

        # Set up kaimei riddles achievements
        achievements = self.data.local.user.get_achievements(
            self.game, self.version, userid
        )
        for achievement in achievements:
            if achievement.type == "riddle":
                kaimei_gauge = achievement.data.get_int("kaimei_gauge")
                is_cleared = achievement.data.get_bool("is_cleared")
                riddles_cleared = achievement.data.get_bool("riddles_cleared")
                select_count = achievement.data.get_int("select_count")
                other_count = achievement.data.get_int("other_count")

                sp_riddles = Node.void("sp_riddles")
                riddles_data.add_child(sp_riddles)
                sp_riddles.add_child(Node.u16("kaimei_gauge", kaimei_gauge))
                sp_riddles.add_child(Node.bool("is_cleared", is_cleared))
                sp_riddles.add_child(Node.bool("riddles_cleared", riddles_cleared))
                sp_riddles.add_child(Node.u8("select_count", select_count))
                sp_riddles.add_child(Node.u32("other_count", other_count))

        return root

    def unformat_profile(
        self, userid: UserID, request: Node, oldprofile: Profile
    ) -> Profile:
        newprofile = super().unformat_profile(userid, request, oldprofile)

        account = request.child("account")
        if account is not None:
            newprofile.replace_int(
                "card_again_count", account.child_value("card_again_count")
            )
            newprofile.replace_int(
                "sp_riddles_id", account.child_value("sp_riddles_id")
            )

        # Kaimei riddles events
        event2021 = request.child("event2021")
        if event2021 is not None:
            newprofile.replace_int("point", event2021.child_value("point"))
            newprofile.replace_int("step", event2021.child_value("step"))
            newprofile.replace_int_array(
                "quest_point", 8, event2021.child_value("quest_point")
            )
            newprofile.replace_int("step_nos", event2021.child_value("step_nos"))
            newprofile.replace_int_array(
                "quest_point_nos", 13, event2021.child_value("quest_point_nos")
            )

        # Extract kaimei riddles achievements
        for node in request.children:
            if node.name == "riddles_data":
                riddle_id = 0
                playedRiddle = request.child("account").child_value("sp_riddles_id")
                for riddle in node.children:
                    kaimei_gauge = riddle.child_value("kaimei_gauge")
                    is_cleared = riddle.child_value("is_cleared")
                    riddles_cleared = riddle.child_value("riddles_cleared")
                    select_count = riddle.child_value("select_count")
                    other_count = riddle.child_value("other_count")

                    if riddles_cleared or select_count >= 3:
                        select_count = 3
                    elif playedRiddle == riddle_id:
                        select_count += 1

                    self.data.local.user.put_achievement(
                        self.game,
                        self.version,
                        userid,
                        riddle_id,
                        "riddle",
                        {
                            "kaimei_gauge": kaimei_gauge,
                            "is_cleared": is_cleared,
                            "riddles_cleared": riddles_cleared,
                            "select_count": select_count,
                            "other_count": other_count,
                        },
                    )

                    riddle_id += 1

        return newprofile
