import seaborn
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.forms import modelformset_factory
#from django.views import generic
from django.contrib.auth.decorators import login_required, permission_required
from website.settings import APPLICATION_NAME
from rotbot.models import Network, Host, Channel, User, Message, Action, Notice, Join, Kick, CurseWord, Adjective
from rotbot.forms import CurseWordForm, AdjectiveForm
from rotbot.views.common import default_keywords, shorten_number, total_messages

# Common
def user_stats(name, event_stats, stats=False):
    if not stats:
        stats = {}
    if not event_stats:
        for stat in stats:
            stats[stat][name] = 0
    for stat in event_stats:
        if not stat.channel.name in stats:
            stats[stat.channel.name] = {}
        stats[stat.channel.name][name] = stat.amount
    return stats



def index(request):
    networks = Network.objects.all()
    hosts = Host.objects.all()
    channels = Channel.objects.all()
    users = User.objects.all()
    joins = Join.objects.all()
    kicks = Kick.objects.all()
    messages = Message.objects.all()
    actions = Action.objects.all()
    notices = Notice.objects.all()
    cursewords = CurseWord.objects.all()

    context = {
        'title': 'RotBot',
        'icon': 'hashtag',
        'description': 'Index of RotBot',
        'keywords': default_keywords('index'),
        'total_networks':shorten_number(networks.count()),
        'total_hosts':shorten_number(hosts.count()),
        'total_channels':shorten_number(channels.count()),
        'total_users':shorten_number(users.count()),
        'total_joins':shorten_number(joins.count()),
        'total_kicks':shorten_number(kicks.count()),
        'total_messages':shorten_number(messages.count()),
        'total_actions':shorten_number(actions.count()),
        'total_notices':shorten_number(notices.count()),
        'total_cursewords':shorten_number(cursewords.count()),
    }
    return render(request, 'rotbot/index.html', context)


def user(request, user_slug):
    user = get_object_or_404(User, slug=user_slug)
    network = Network.objects.get(id=user.network.id)
    messages = Message.objects.filter(user=user)
    actions = Action.objects.filter(user=user)
    notices = Notice.objects.filter(user=user)
    joins = Join.objects.filter(user=user)
    kicks = Kick.objects.filter(kicker=user)
    kicked = Kick.objects.filter(kicked=user)

    if user.last_event_type == 'pm':
        last_event_type = 'speaking privately'
    if user.last_event_type == 'pa':
        last_event_type = 'sending a private action'
    if user.last_event_type == 'pn':
        last_event_type = 'sending a private notice'
    if user.last_event_type == 'cm':
        last_event_type = 'speaking publicly'
    if user.last_event_type == 'ca':
        last_event_type = 'sending a public action'
    if user.last_event_type == 'cn':
        last_event_type = 'sending a public notice'
    if user.last_event_type == 'ct':
        last_event_type = 'changing the topic'
    if user.last_event_type == 'ck':
        last_event_type = 'changing the password'
    if user.last_event_type == 'ci':
        last_event_type = 'inviting'
    if user.last_event_type == 'cj':
        last_event_type = 'joining'
    if user.last_event_type == 'cp':
        last_event_type == 'parting'
    if user.last_event_type == 'ck':
        last_event_type = 'kicking'
    if user.last_event_type == 'kd':
        last_event_type = 'getting kicked'
    if user.last_event_type == 'mc':
        last_event_type = 'changing modes'
    if user.last_event_type == 'nc':
        last_event_type = 'nick change'
    if user.last_event_type =='sq':
        last_event_type = 'quitting'

    stats_dict = None
    stats_dict = user_stats('joins', joins, stats=stats_dict)
    stats_dict = user_stats('messages', messages, stats=stats_dict)
    stats_dict = user_stats('actions', actions, stats=stats_dict)
    stats_dict = user_stats('notices', notices, stats=stats_dict)
    stats_dict = user_stats('kicks', kicks, stats=stats_dict)
    stats_dict = user_stats('kicked', kicked, stats=stats_dict)

    labels = list(list(stats_dict.values())[0].keys())

    datasets = []
    dicts_amount = len(stats_dict)
    color_palette = seaborn.color_palette("husl", dicts_amount * 5)

    i = 0
    for color in color_palette:
        color_list = list(color)
        color_list[0] *= 255
        color_list[1] *= 255
        color_list[2] *= 255
        color_palette[i] = tuple(color_list)
        i += 1


    i = 0
    for dict in stats_dict:
        color_gradient = linear_gradient(color_palette[i], n=4)
        print(color_gradient)
        datasets.append({
            "label": dict,
            "data": list(stats_dict[dict].values()),
            "backgroundColor": 'rgba' + str(color_gradient[i]),#, 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]),],
            "borderColor": 'rgba' + str(color_gradient[i+1]),#, 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]),],
            #"pointBackgroundColor": ['rgba' + str(tuple(color_palette[i+1]))],
            #"pointBorderColor": ['rgba' + str(tuple(color_palette[i+3]))],
            #"pointStrokeColor": ['rgba' + str(tuple(color_palette[i+4]))],
            "hoverBackgroundColor": 'rgba' + str(color_palette[i+2]),#, 'rgba' + str(tuple(color_palette[i+2])), 'rgba' + str(tuple(color_palette[i+2])), 'rgba' + str(tuple(color_palette[i+2])), 'rgba' + str(tuple(color_palette[i+2])),],
            "hoverBorderColor": 'rgba' + str(color_palette[i+3]),#, 'rgba' + str(tuple(color_palette[i+3])), 'rgba' + str(tuple(color_palette[i+3])), 'rgba' + str(tuple(color_palette[i+3])), 'rgba' + str(tuple(color_palette[i+3])),],
            #"hoverWidth": 2,
            "borderWidth": 1,
            #"borderSkipped": False,
        })
        i += 1

    chart =  {
        "type": "bar",
        "data": {
            "labels": labels,
            "datasets": datasets,
        },
        "options": {},
    }
    context = {
        'parent_title': network.name,
        'parent_url': reverse('rotbot:network', args=(network.slug,)),
        'parent_icon': 'sitemap',
        'title': user.name,
        'icon': 'hashtag',
        'description': 'Details of user %s on network %s' % (user.name, network.name),
        'keywords': default_keywords() + '%s, %s' % (network.name, user.name),
        'user': user,
        'network': network,
        'total_messages': shorten_number(total_messages(messages)),
        'total_actions': shorten_number(total_messages(actions)),
        'total_notices': shorten_number(total_messages(notices)),
        'total_joins': shorten_number(joins.count()),
        'total_kicks': shorten_number(kicked.count()),
        'total_kicked': shorten_number(kicked.count()),
        'last_event_type': last_event_type,
        'stats': stats_dict,
        'chart': chart,
    }
    return render(request, 'rotbot/user.html', context)

def color_dict(gradient):
  ''' Takes in a list of RGB sub-lists and returns dictionary of
    colors in RGB and hex form for use in a graphing function
    defined later on '''
  gradients = []
  for RGB in gradient:
      gradients.append(tuple((RGB[0], RGB[1], RGB[2])))

  return tuple(gradients)
# {
#       "r":[RGB[0] for RGB in gradient],
#       "g":[RGB[1] for RGB in gradient],
#       "b":[RGB[2] for RGB in gradient]}


def linear_gradient(start_rgb, finish_hex="#FFFFFF", n=10):
  ''' returns a gradient list of (n) colors between
    two hex colors. start_hex and finish_hex
    should be the full six-digit color string,
    inlcuding the number sign ("#FFFFFF") '''
  # Starting and ending colors in RGB form
  #s = hex_to_RGB(start_hex)
  print(n)
  s = start_rgb
  f = hex_to_RGB(finish_hex)
  # Initilize a list of the output colors with the starting color
  RGB_list = [s]
  # Calcuate a color at each evenly spaced value of t from 1 to n
  for t in range(1, n):
    # Interpolate RGB vector for color at the current value of t
    curr_vector = [
      int(s[j] + (float(t)/(n-1))*(f[j]-s[j]))
      for j in range(3)
    ]
    # Add it to our list of output colors
    RGB_list.append(curr_vector)

  return color_dict(RGB_list)

def hex_to_RGB(hex):
  ''' "#FFFFFF" -> [255,255,255] '''
  # Pass 16 to the integer function for change of base
  return [int(hex[i:i+2], 16) for i in range(1,6,2)]


def RGB_to_hex(RGB):
  ''' [255,255,255] -> "#FFFFFF" '''
  # Components need to be integers for hex to make sense
  RGB = [int(x) for x in RGB]
  return "#"+"".join(["0{0:x}".format(v) if v < 16 else
            "{0:x}".format(v) for v in RGB])

# from jchart import Chart
# from jchart.config import DataSet
#

# class LineChart(Chart):
#
#     chart_type = 'line'
#
#     def get_datasets(self, channel_dict, **kwargs):
#         print(channel_dict)
#         data = []
#         for channel in channel_dict:
#             print(channel)
#             print(channel_dict[channel])
#             print(list(channel_dict[channel].values()))
#             print(channel_dict[channel].keys())
#             list(channel_dict[channel].values())
#             data.append(list(channel_dict[channel].values()))
#             print(data)
#
#             a = DataSet(
#                 data=data[0]
#             )
#             foobar = []
#             for d in data:
#                 foobar.append(d)
#         return a
#         # [
#         # DataSet(
#         #     data=data,
#         #     #color=(55,55,55),
#         # )]
#         # [
#         #     DataSet(
#         #         data = [69, 30],
#         #         #data = data
#         #         color = (255,255,255)
#         #     ),
#         #     DataSet(
#         #         data = [29, 70],
#         #         #data = data
#         #         color = (125,125,125)
#         #     ),
#         # ]
#
#     def get_labels(self, channel_dict, **kwargs):
#
#         return ['Red', 'Blue']


@login_required
@permission_required('rotbot.add_curseword', raise_exception=True)
def add_curseword(request):
    CurseWordFormSet = modelformset_factory(CurseWord, form=CurseWordForm, extra=4)
    AdjectiveFormSet = modelformset_factory(Adjective, form=AdjectiveForm, extra=4)
    if request.method == 'POST':
        curseword_formset = CurseWordFormSet(request.POST)
        Adjective_formset = AdjectiveFormSet(request.POST)
        if curseword_formset.is_valid() and Adjective_formset.is_valid():
            curseword_formset.save()
            Adjective_formset.save()
            return HttpResponseRedirect(reverse('rotbot:networks'))
        else:
            curseword_formset = CurseWordFormSet(queryset=CurseWord.objects.none())
            Adjective_formset = CurseWordFormSet(queryset=Adjective.objects.none())
    else:   # Not a POST request.
        curseword_formset = CurseWordFormSet(queryset=CurseWord.objects.none())
        Adjective_formset = AdjectiveFormSet(queryset=Adjective.objects.none())

    context = {
        'parent_title': 'RotBot',
        'parent_url': reverse('rotbot:networks'),
        'parent_icon': 'sitemap',
        'title': 'Add curseword',
        'icon': 'book dead',
        'description': 'Add a curseword to RotBot\'s vocabulary.',
        'keywords': default_keywords(),
        'curseword_formset': curseword_formset,
        'Adjective_formset': Adjective_formset,
    }
    return render(request, 'rotbot/add_curseword.html', context)
