from json import dumps, loads
from time import sleep
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from constants import REQUEST_HEADERS, WAIT_INTERVAL


class AttributeParser:
    def __init__(self):
        self.ability_urls = []
        self.move_urls = []
        self.failed_urls = []

    @staticmethod
    def get_pokedex_numbers(nums):
        result = []
        for i in nums:
            result.append(
                {'entryNumber': i['entry_number'], 'pokedex': i['pokedex']['name']})
        return result

    @staticmethod
    def get_varieties(varieties):
        result = []
        for i in varieties:
            result.append({'isDefault': i['is_default'], 'pokemon': i['pokemon']['name']})
        return result

    @staticmethod
    def get_forms(forms):
        result = []
        for i in forms:
            result.append(i['name'])
        return result

    def get_abilities(self, abilities):
        result = []
        for each in abilities:
            if each['ability']['url'] not in self.ability_urls:
                self.ability_urls.append(each['ability']['url'])
            result.append({
                'ability': each['ability']['name'],
                'isHidden': each['is_hidden'],
                'slot': each['slot']
            })
        return result

    @staticmethod
    def get_indices(indices):
        result = []
        for index in indices:
            result.append({
                'gameIndex': index['game_index'],
                'version': index['version']['name']
            })
        return result

    @staticmethod
    def get_version_group_details(group_details):
        result = []
        for detail in group_details:
            result.append({
                'levelLearnedAt': detail['level_learned_at'],
                'moveLearnMethod': detail['move_learn_method']['name'],
                'versionGroup': detail['version_group']['name']
            })
        return result

    def get_moves(self, moves):
        result = []
        for move in moves:
            if move['move']['url'] not in self.move_urls:
                self.move_urls.append(move['move']['url'])
            result.append({
                'move': move['move']['name'],
                'versionGroupDetails': self.get_version_group_details(move['version_group_details']),
            })
        return result

    @staticmethod
    def get_stats(stats):
        result = {}
        for stat in stats:
            name = stat['stat']['name']
            if '-' in name:
                name = name[:name.find('-')] + name[name.find('-') + 1].upper() + name[name.find('-') + 2:]

            result[name] = stat['base_stat']
            result[f'{name}Effort'] = stat['effort']

        return result

    @staticmethod
    def get_types(types):
        if len(types) == 1:
            return [types[0]['type']['name']]
        return [types[1]['type']['name'], types[0]['type']['name']]

    @staticmethod
    def get_egg_groups(egg_groups):
        if len(egg_groups) == 1:
            return [egg_groups[0]['name']]
        return [egg_groups[1]['name'], egg_groups[0]['name']]

    @staticmethod
    def get_description(effect_entries):
        for item in effect_entries:
            if item['language']['name'] == 'en':
                return item['short_effect']
        return ''

    @staticmethod
    def get_metadata(meta):
        result = {}
        for key, value in meta.items():
            if key == 'ailment' or key == 'category':
                result[key] = value['name']
            else:
                result[key] = value
        return result

    def rename_pokemon_attributes(self, pokemon_to_rename):
        return {
            'name': pokemon_to_rename['name'],
            'genderRate': pokemon_to_rename['gender_rate'],
            'captureRate': pokemon_to_rename['capture_rate'],
            'isBaby': pokemon_to_rename['is_baby'],
            'hatchCounter': pokemon_to_rename['hatch_counter'],
            'growthRate': pokemon_to_rename['growth_rate']['name'],
            'pokedexNumbers': self.get_pokedex_numbers(pokemon_to_rename['pokedex_numbers']),
            'eggGroups': self.get_egg_groups(pokemon_to_rename['egg_groups']),
            'evolutionChain': pokemon_to_rename['evolution_chain'],
            'varieties': self.get_varieties(pokemon_to_rename['varieties']),
            'abilities': self.get_abilities(pokemon_to_rename['abilities']),
            'forms': self.get_forms(pokemon_to_rename['forms']),
            'gameIndices': self.get_indices(pokemon_to_rename['game_indices']),
            # 'moves': self.get_moves(pokemon_to_rename['moves']),
            'stats': self.get_stats(pokemon_to_rename['stats']),
            'types': self.get_types(pokemon_to_rename['types']),
        }

    def fetch_abilities(self):
        ability_info = []
        for url in self.ability_urls:
            sleep(WAIT_INTERVAL)
            try:
                print('Fetching info about an ability')
                response = loads(urlopen(Request(url, headers=REQUEST_HEADERS)).read().decode())
                ability_info.append({
                    'effect': response['effect_entries'][0]['short_effect'],
                    'generation': response['generation']['name'],
                    'name': response['name']
                })
            except HTTPError:
                print(f'Could not fetch information about ability from url {url}')
                self.failed_urls.append(url)
                sleep(WAIT_INTERVAL)
        with open('ability_info.json', 'w') as file_writer:
            file_writer.write(dumps(ability_info))
            del self.ability_urls

    def fetch_moves(self):
        move_info = []
        for url in self.move_urls:
            sleep(WAIT_INTERVAL)
            print(f'Fetching info about a move {self.move_urls.index(url)}')
            try:
                response = loads(urlopen(Request(url, headers=REQUEST_HEADERS)).read().decode())
                move_info.append({
                    'accuracy': response['accuracy'],
                    'class': response['damage_class']['name'],
                    'effectChance': response['effect_chance'],
                    'powerPoints': response['pp'],
                    'priority': response['priority'],
                    'power': response['power'],
                    'description': self.get_description(response['effect_entries']),
                    'generation': response['generation']['name'],
                    'metadata': self.get_metadata(response['meta']),
                    'type': response['type']['name'],
                    'name': response['name']
                })
            except HTTPError:
                print(f'Could not fetch data about move from url {url}')
                self.failed_urls.append(url)
                sleep(WAIT_INTERVAL)
        with open('move_info.json', 'w') as file_writer:
            file_writer.write(dumps(move_info))
            del self.move_urls

from json import dumps, loads
from time import sleep
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from constants import REQUEST_HEADERS, WAIT_INTERVAL


class AttributeParser:
    def __init__(self):
        self.ability_urls = []
        self.move_urls = []
        self.failed_urls = []

    @staticmethod
    def get_pokedex_numbers(nums):
        result = []
        for i in nums:
            result.append(
                {'entryNumber': i['entry_number'], 'pokedex': i['pokedex']['name']})
        return result

    @staticmethod
    def get_varieties(varieties):
        result = []
        for i in varieties:
            result.append({'isDefault': i['is_default'], 'pokemon': i['pokemon']['name']})
        return result

    @staticmethod
    def get_forms(forms):
        result = []
        for i in forms:
            result.append(i['name'])
        return result

    def get_abilities(self, abilities):
        result = []
        for each in abilities:
            if each['ability']['url'] not in self.ability_urls:
                self.ability_urls.append(each['ability']['url'])
            result.append({
                'ability': each['ability']['name'],
                'isHidden': each['is_hidden'],
                'slot': each['slot']
            })
        return result

    @staticmethod
    def get_indices(indices):
        result = []
        for index in indices:
            result.append({
                'gameIndex': index['game_index'],
                'version': index['version']['name']
            })
        return result

    @staticmethod
    def get_version_group_details(group_details):
        result = []
        for detail in group_details:
            result.append({
                'levelLearnedAt': detail['level_learned_at'],
                'moveLearnMethod': detail['move_learn_method']['name'],
                'versionGroup': detail['version_group']['name']
            })
        return result

    def get_moves(self, moves):
        result = []
        for move in moves:
            if move['move']['url'] not in self.move_urls:
                self.move_urls.append(move['move']['url'])
            result.append({
                'move': move['move']['name'],
                'versionGroupDetails': self.get_version_group_details(move['version_group_details']),
            })
        return result

    @staticmethod
    def get_stats(stats):
        result = {}
        for stat in stats:
            name = stat['stat']['name']
            if '-' in name:
                name = name[:name.find('-')] + name[name.find('-') + 1].upper() + name[name.find('-') + 2:]

            result[name] = stat['base_stat']
            result[f'{name}Effort'] = stat['effort']

        return result

    @staticmethod
    def get_types(types):
        if len(types) == 1:
            return [types[0]['type']['name']]
        return [types[1]['type']['name'], types[0]['type']['name']]

    @staticmethod
    def get_egg_groups(egg_groups):
        if len(egg_groups) == 1:
            return [egg_groups[0]['name']]
        return [egg_groups[1]['name'], egg_groups[0]['name']]

    @staticmethod
    def get_description(effect_entries):
        for item in effect_entries:
            if item['language']['name'] == 'en':
                return item['short_effect']
        return ''

    @staticmethod
    def get_metadata(meta):
        result = {}
        for key, value in meta.items():
            if key == 'ailment' or key == 'category':
                result[key] = value['name']
            else:
                result[key] = value
        return result

    def rename_pokemon_attributes(self, pokemon_to_rename):
        return {
            'name': pokemon_to_rename['name'],
            'genderRate': pokemon_to_rename['gender_rate'],
            'captureRate': pokemon_to_rename['capture_rate'],
            'isBaby': pokemon_to_rename['is_baby'],
            'hatchCounter': pokemon_to_rename['hatch_counter'],
            'growthRate': pokemon_to_rename['growth_rate']['name'],
            'pokedexNumbers': self.get_pokedex_numbers(pokemon_to_rename['pokedex_numbers']),
            'eggGroups': self.get_egg_groups(pokemon_to_rename['egg_groups']),
            'evolutionChain': pokemon_to_rename['evolution_chain'],
            'varieties': self.get_varieties(pokemon_to_rename['varieties']),
            'abilities': self.get_abilities(pokemon_to_rename['abilities']),
            'forms': self.get_forms(pokemon_to_rename['forms']),
            'gameIndices': self.get_indices(pokemon_to_rename['game_indices']),
            # 'moves': self.get_moves(pokemon_to_rename['moves']),
            'stats': self.get_stats(pokemon_to_rename['stats']),
            'types': self.get_types(pokemon_to_rename['types']),
        }

    def fetch_abilities(self):
        ability_info = []
        for url in self.ability_urls:
            sleep(WAIT_INTERVAL)
            try:
                print('Fetching info about an ability')
                response = loads(urlopen(Request(url, headers=REQUEST_HEADERS)).read().decode())
                ability_info.append({
                    'effect': response['effect_entries'][0]['short_effect'],
                    'generation': response['generation']['name'],
                    'name': response['name']
                })
            except HTTPError:
                print(f'Could not fetch information about ability from url {url}')
                self.failed_urls.append(url)
                sleep(WAIT_INTERVAL)
        with open('ability_info.json', 'w') as file_writer:
            file_writer.write(dumps(ability_info))
            del self.ability_urls

    def fetch_moves(self):
        move_info = []
        for url in self.move_urls:
            sleep(WAIT_INTERVAL)
            print(f'Fetching info about a move {self.move_urls.index(url)}')
            try:
                response = loads(urlopen(Request(url, headers=REQUEST_HEADERS)).read().decode())
                move_info.append({
                    'accuracy': response['accuracy'],
                    'class': response['damage_class']['name'],
                    'effectChance': response['effect_chance'],
                    'powerPoints': response['pp'],
                    'priority': response['priority'],
                    'power': response['power'],
                    'description': self.get_description(response['effect_entries']),
                    'generation': response['generation']['name'],
                    'metadata': self.get_metadata(response['meta']),
                    'type': response['type']['name'],
                    'name': response['name']
                })
            except HTTPError:
                print(f'Could not fetch data about move from url {url}')
                self.failed_urls.append(url)
                sleep(WAIT_INTERVAL)
        with open('move_info.json', 'w') as file_writer:
            file_writer.write(dumps(move_info))
            del self.move_urls

# 'moves': self.get_moves(pokemon_to_rename['moves']),