# This generates a 'realistic' example dataset as far as possible to be used as
# an example for the optimizer.
#
# Assumes a file called 'games.json' exists in the same directory, as would be
# generated by game_data.py

import json

from faker import Faker
import numpy as np


# No Belgium locale sadly :( but we use this to generate some pan-european
# names :)
LOCALES = [
    'nl_NL',
    'fr_FR',
    'it_IT',
    'de_DE',
    'en_GB',
    'es_ES',
    'cs_CZ',
    'dk_DK',
    'sv_SE',
    'pl_PL',
]

FAKES = [Faker(l) for l in LOCALES]


def fake():
    """Return a faker from a random locale"""
    return FAKES[np.random.choice(len(LOCALES))]


def names(n=40):
    """Return a set of first names."""
    name_set = set()

    while len(name_set) < n:
        name_set.add(fake().first_name())

    return name_set


def random_games(n, games_db, games_distribution):
    """Draw random games from the games db, without replacement (i.e. unique choices)"""
    games = np.random.choice(
        games_db,
        size=n,
        replace=False,
        p=games_distribution
    )

    return [g['name'] for g in games]


def owned_games(games_db, games_distribution):
    """Return games people own.

    Weighted such that most people don't bring any games.
    """
    n = np.random.choice(6, p=[0.5, 0.2, 0.1, 0.1, 0.05, 0.05])

    return random_games(n, games_db, games_distribution)


def want_to_play(games_db, games_owned, games_distribution):
    """Return games people want to play.

    Assume that if you own/bring a game, you want to play it.
    """
    n = np.random.choice(8)
    return list(set(games_owned + random_games(n, games_db, games_distribution)))


def sessions(n_max):
    """Returns the sessions a person will be attending.

    Most people will attend all sessions, others will attend a random
    contiguous subset of sessions.

    """
    p = [0.3 / (n_max-1)] * (n_max - 1)
    p.append(0.7)

    n = np.random.choice(n_max, p=p) + 1

    if n < n_max:
        a = np.random.choice(n_max - n + 1)
    else:
        a = 0

    return list(range(n_max))[a:(a+n)]


def make_games_distribution(games_db):
    """Return the probability distribution of owning / wanting to play a game

    This is based on the proportion of 'owned' games on BGG.
    """
    total_owned = sum([g['owned'] for g in games_db])

    return [g['owned'] / total_owned for g in games_db]


if __name__ == '__main__':
    with open('games.json', 'r') as f:
        games_db = json.load(f)

    games_db = sorted(games_db, key=lambda g: g['owned'], reverse=True)
    games_distribution = make_games_distribution(games_db)
    people = names()
    result = []

    for person in people:
        games_owned = owned_games(games_db, games_distribution)

        result.append({
            'name': person,
            'owns': games_owned,
            'interests': want_to_play(games_db, games_owned, games_distribution),
            'sessions': sessions(4),
        })

    with open('sample.json', 'w') as f:
        json.dump(result, f, indent=2)
