from collections import Counter, defaultdict
from itertools import cycle
from datetime import datetime, timedelta, date
from math import tau

from bokeh.embed import components
from bokeh.palettes import Dark2_8 as palette
from bokeh.plotting import figure, ColumnDataSource
from bokeh.resources import INLINE
from flask import render_template
from pony.orm import select

from . import app, cache
from .models import Room


def get_db_data():
    games_played = defaultdict(Counter)
    total_games = Counter()
    cutoff = date.today()-timedelta(days=30000)
    room: Room
    for room in select(room for room in Room if room.creation_time >= cutoff):
        for slot in room.seed.slots:
            total_games[slot.game] += 1
            games_played[room.creation_time.date()][slot.game] += 1
    return total_games, games_played


@app.route('/stats')
@cache.memoize(timeout=60*60)  # regen once per hour should be plenty
def stats():
    plot = figure(title="Games Played Per Day", x_axis_type='datetime', x_axis_label="Date",
                  y_axis_label="Games Played", sizing_mode="scale_both", width=500, height=500)

    total_games, games_played = get_db_data()
    days = sorted(games_played)

    cyc_palette = cycle(palette)

    for game in sorted(total_games):
        occurences = []
        for day in days:
            occurences.append(games_played[day][game])
        plot.line([datetime.combine(day, datetime.min.time()) for day in days],
                  occurences, legend_label=game, line_width=2, color=next(cyc_palette))

    total = sum(total_games.values())
    pie = figure(plot_height=350, title=f"Games Played in the Last 30 Days (Total: {total})", toolbar_location=None,
                 tools="hover", tooltips=[("Game:", "@games"), ("Played:", "@count")],
                 sizing_mode="scale_both", width=500, height=500)
    pie.axis.visible = False

    data = {
        "games": [],
        "count": [],
        "start_angles": [],
        "end_angles": [],
    }
    current_angle = 0
    for i, (game, count) in enumerate(total_games.most_common()):
        data["games"].append(game)
        data["count"].append(count)
        data["start_angles"].append(current_angle)
        angle = count / total * tau
        current_angle += angle
        data["end_angles"].append(current_angle)

    data["colors"] = [element[1] for element in sorted((game, color) for game, color in
                                                       zip(data["games"], cycle(palette)))]
    pie.wedge(x=0.5, y=0.5, radius=0.5,
              start_angle="start_angles", end_angle="end_angles", fill_color="colors",
              source=ColumnDataSource(data=data), legend_field="games")

    script, charts = components((plot, pie))
    return render_template("stats.html", js_resources=INLINE.render_js(), css_resources=INLINE.render_css(),
                           chart_data=script, charts=charts)