import random
import uuid

import factory
import persisting_theory
from django.conf import settings
from faker.providers import internet as internet_provider


class FactoriesRegistry(persisting_theory.Registry):
    look_into = "factories"

    def prepare_name(self, data, name=None):
        return name or data._meta.model._meta.label


registry = FactoriesRegistry()


def ManyToManyFromList(field_name):
    """
    To automate the pattern described in
    http://factoryboy.readthedocs.io/en/latest/recipes.html#simple-many-to-many-relationship
    """

    @factory.post_generation
    def inner(self, create, extracted, **kwargs):
        if not create:
            return

        if extracted:
            field = getattr(self, field_name)
            field.add(*extracted)

    return inner


class NoUpdateOnCreate:
    """
    Factory boy calls save after the initial create. In most case, this
    is not needed, so we disable this behaviour
    """

    @classmethod
    def _after_postgeneration(cls, instance, create, results=None):
        return


TAGS_DATA = {
    "type": [
        "acoustic",
        "acid",
        "ambient",
        "alternative",
        "brutalist",
        "chill",
        "club",
        "cold",
        "cool",
        "contemporary",
        "dark",
        "doom",
        "electro",
        "folk",
        "freestyle",
        "fusion",
        "garage",
        "glitch",
        "hard",
        "healing",
        "industrial",
        "instrumental",
        "hardcore",
        "holiday",
        "hot",
        "liquid",
        "modern",
        "minimalist",
        "new",
        "parody",
        "postmodern",
        "progressive",
        "smooth",
        "symphonic",
        "traditional",
        "tribal",
        "metal",
    ],
    "genre": [
        "blues",
        "classical",
        "chiptune",
        "dance",
        "disco",
        "funk",
        "jazz",
        "house",
        "hiphop",
        "NewAge",
        "pop",
        "punk",
        "rap",
        "RnB",
        "reggae",
        "rock",
        "soul",
        "soundtrack",
        "ska",
        "swing",
        "trance",
    ],
    "nationality": [
        "Afghan",
        "Albanian",
        "Algerian",
        "American",
        "Andorran",
        "Angolan",
        "Antiguans",
        "Argentinean",
        "Armenian",
        "Australian",
        "Austrian",
        "Azerbaijani",
        "Bahamian",
        "Bahraini",
        "Bangladeshi",
        "Barbadian",
        "Barbudans",
        "Batswana",
        "Belarusian",
        "Belgian",
        "Belizean",
        "Beninese",
        "Bhutanese",
        "Bolivian",
        "Bosnian",
        "Brazilian",
        "British",
        "Bruneian",
        "Bulgarian",
        "Burkinabe",
        "Burmese",
        "Burundian",
        "Cambodian",
        "Cameroonian",
        "Canadian",
        "Cape Verdean",
        "Central African",
        "Chadian",
        "Chilean",
        "Chinese",
        "Colombian",
        "Comoran",
        "Congolese",
        "Costa Rican",
        "Croatian",
        "Cuban",
        "Cypriot",
        "Czech",
        "Danish",
        "Djibouti",
        "Dominican",
        "Dutch",
        "East Timorese",
        "Ecuadorean",
        "Egyptian",
        "Emirian",
        "Equatorial Guinean",
        "Eritrean",
        "Estonian",
        "Ethiopian",
        "Fijian",
        "Filipino",
        "Finnish",
        "French",
        "Gabonese",
        "Gambian",
        "Georgian",
        "German",
        "Ghanaian",
        "Greek",
        "Grenadian",
        "Guatemalan",
        "Guinea-Bissauan",
        "Guinean",
        "Guyanese",
        "Haitian",
        "Herzegovinian",
        "Honduran",
        "Hungarian",
        "I-Kiribati",
        "Icelander",
        "Indian",
        "Indonesian",
        "Iranian",
        "Iraqi",
        "Irish",
        "Israeli",
        "Italian",
        "Ivorian",
        "Jamaican",
        "Japanese",
        "Jordanian",
        "Kazakhstani",
        "Kenyan",
        "Kittian and Nevisian",
        "Kuwaiti",
        "Kyrgyz",
        "Laotian",
        "Latvian",
        "Lebanese",
        "Liberian",
        "Libyan",
        "Liechtensteiner",
        "Lithuanian",
        "Luxembourger",
        "Macedonian",
        "Malagasy",
        "Malawian",
        "Malaysian",
        "Maldivian",
        "Malian",
        "Maltese",
        "Marshallese",
        "Mauritanian",
        "Mauritian",
        "Mexican",
        "Micronesian",
        "Moldovan",
        "Monacan",
        "Mongolian",
        "Moroccan",
        "Mosotho",
        "Motswana",
        "Mozambican",
        "Namibian",
        "Nauruan",
        "Nepalese",
        "New Zealander",
        "Ni-Vanuatu",
        "Nicaraguan",
        "Nigerian",
        "Nigerien",
        "North Korean",
        "Northern Irish",
        "Norwegian",
        "Omani",
        "Pakistani",
        "Palauan",
        "Panamanian",
        "Papua New Guinean",
        "Paraguayan",
        "Peruvian",
        "Polish",
        "Portuguese",
        "Qatari",
        "Romanian",
        "Russian",
        "Rwandan",
        "Saint Lucian",
        "Salvadoran",
        "Samoan",
        "San Marinese",
        "Sao Tomean",
        "Saudi",
        "Scottish",
        "Senegalese",
        "Serbian",
        "Seychellois",
        "Sierra Leonean",
        "Singaporean",
        "Slovakian",
        "Slovenian",
        "Solomon Islander",
        "Somali",
        "South African",
        "South Korean",
        "Spanish",
        "Sri Lankan",
        "Sudanese",
        "Surinamer",
        "Swazi",
        "Swedish",
        "Swiss",
        "Syrian",
        "Taiwanese",
        "Tajik",
        "Tanzanian",
        "Thai",
        "Togolese",
        "Tongan",
        "Trinidadian",
        "Tunisian",
        "Turkish",
        "Tuvaluan",
        "Ugandan",
        "Ukrainian",
        "Uruguayan",
        "Uzbekistani",
        "Venezuelan",
        "Vietnamese",
        "Welsh",
        "Yemenite",
        "Zambian",
        "Zimbabwean",
    ],
}


class FunkwhaleProvider(internet_provider.Provider):
    """
    Our own faker data generator, since built-in ones are sometimes
    not random enough
    """

    def federation_url(self, prefix="", obj_uuid=None, local=False):
        if not obj_uuid:
            obj_uuid = uuid.uuid4()

        def path_generator():
            return f"{prefix}/{obj_uuid}"

        domain = settings.FEDERATION_HOSTNAME if local else self.domain_name()
        protocol = "https"
        path = path_generator()
        return f"{protocol}://{domain}/{path}"

    def user_name(self):
        u = super().user_name()
        return f"{u}{random.randint(10, 999)}"

    def music_genre(self):
        return random.choice(TAGS_DATA["genre"])

    def music_type(self):
        return random.choice(TAGS_DATA["type"])

    def music_nationality(self):
        return random.choice(TAGS_DATA["nationality"])

    def music_hashtag(self, prefix_length=4):
        genre = self.music_genre()
        prefixes = [genre]
        nationality = False
        while len(prefixes) < prefix_length:
            if nationality:
                t = "type"
            else:
                t = random.choice(["type", "nationality", "genre"])

            if t == "nationality":
                nationality = True

            choice = random.choice(TAGS_DATA[t])
            if choice in prefixes:
                continue
            prefixes.append(choice)

        return "".join(
            [p.capitalize().strip().replace(" ", "") for p in reversed(prefixes)]
        )


factory.Faker.add_provider(FunkwhaleProvider)
