# All the Team related methods

# Python
from django.utils import timezone
from datetime import datetime
from datetime import timedelta
import time
from django.db import IntegrityError
import uuid
from django.conf import settings


import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')

from rowers.models import (
    Rower, Workout, Team, TeamInvite,User,TeamRequest
    )

from rowers.tasks import (
    handle_sendemail_invite,
    handle_sendemail_request,
    handle_sendemail_member_dropped,handle_sendemail_request_accept,
    handle_sendemail_request_reject,handle_sendemail_invite_reject,
    handle_sendemail_invite_accept,handle_sendemail_team_removed,
    )

# Low level functions - to be called by higher level methods

inviteduration = 14 # days

def handle_remove_workouts_team(ws,t):
    for w in ws:
        w.team.remove(t)

    return 1

def handle_add_workouts_team(ws,t):
    
    for w in ws:
        w.team.add(t)

    return 1

def update_team(t,name,manager,private,notes,viewing):
    if t.manager != manager:
        return (0,'You are not the manager of this team')
    try:
        t.name = name
        t.manager = manager
        t.private = private
        t.notes = notes
        t.viewing = viewing
        t.save()
    except IntegrityError:
        return (0,'Team name duplication')
    return (1,'Team Updated')

def create_team(name,manager,private='open',notes='',viewing='allmembers'):
    # needs some error testing
    try:
        t = Team(name=name,manager=manager,notes=notes,
                 private=private,viewing=viewing)
        t.save()
        r = Rower.objects.get(user=manager)
        res = add_member(t.id,r)
    except IntegrityError:
        return (0,'Team name duplication')
    return (t.id,'Team created')

def remove_team(id):
    t = Team.objects.get(id=id)
    for r in Rower.objects.filter(team=t):
        send_team_delete_mail(t,r)
    return t.delete()

def set_teamplanexpires(rower):
    ts = Team.objects.filter(rower=rower)

    texp = datetime.date(timezone.now())

    for t in ts:
        mr = Rower.objects.get(user=t.manager)
        if mr.teamplanexpires > texp:
            rower.teamplanexpires = mr.teamplanexpires

        t.save()

    return (1,'Updated rower team expiry')

def add_member(id,rower):
    t= Team.objects.get(id=id)
    rower.team.add(t)
    # code to add all workouts
    ws = Workout.objects.filter(user=rower)
    
    res = handle_add_workouts_team(ws,t)

    set_teamplanexpires(rower)
        
    return (id,'Member added')

def remove_member(id,rower):
    t = Team.objects.get(id=id)
    rower.team.remove(t)
    # remove the team from rower's workouts:
    ws = Workout.objects.filter(user=rower,team=t)

    res = handle_remove_workouts_team(ws,t)
            
    set_teamplanexpires(rower)
    return (id,'Member removed')

def mgr_remove_member(id,manager,rower):
    t = Team.objects.get(id=id)
    if t.manager == manager:
        remove_member(id,rower)
        send_email_member_dropped(id,rower)
        return (id,'Member removed')
    else:
        return (0,'You are not the team manager')

    return (0,'')

def count_invites(manager):
    ts = Team.objects.filter(manager=manager)
    count = 0
    for t in ts:
        count += TeamInvite.objects.filter(team=t).count()

    return count

def count_members(id):
    t = Team.objects.get(id=id)
    return Rower.objects.filter(team=t).count()

def count_club_members(manager):
    ts = Team.objects.filter(manager=manager)
    return Rower.objects.filter(team__in=ts).distinct().count()

def get_club_members(manager):
    ts = Team.objects.filter(manager=manager)
    return Rower.objects.filter(team__in=ts).distinct()

def get_team_members(id):
    t = Team.objects.get(id=id)
    return Rower.objects.filter(team=t)

def get_team_workouts(id):
    t = Team.objects.get(id=id)
    return Workout.objects.filter(team=t).order_by("-date", "-starttime")

# Medium level functionality

def create_request(team,user):
    r2 = Rower.objects.get(user=user)
    r = Rower.objects.get(user=team.manager)
    if r2 in Rower.objects.filter(team=team):
        return (0,'Already a member of that team')

    if count_club_members(team.manager)+count_invites(team.manager) <= r.clubsize:
        codes = [i.code for i in TeamRequest.objects.all()]
        code = uuid.uuid4().hex[:10].upper()
        # prevent duplicates
        while code in codes:
            code = uuid.uuid4().hex[:10].upper()

        u = User.objects.get(id=user)
        rekwest = TeamRequest(team=team,user=u,code=code)
        rekwest.save()

        send_request_email(rekwest)
        
        return (rekwest.id,'The request was created')
    else:
        return (0,'That team has reached its maximum number of members')
    
    return (0,'Something went wrong in create_request')
    
def create_invite(team,manager,user=None,email=''):
    r = Rower.objects.get(user=manager)
    if team.manager != manager:
        return (0,'Not the team manager')
    if user:
        try:
            r2 = Rower.objects.get(user=user)
        except Rower.DoesNotExist:
            return (0,'Rower does not exist')
        if r2 in Rower.objects.filter(team=team):
            return (0,'Already member of that team')
    elif email==None or email=='':
        return (0,'Invalid request - missing email or user')
    else:
        try:
            r2 = Rower.objects.get(user__email=email)
            user = User.objects.get(rower=r2)
        except Rower.DoesNotExist:
            user=None
        except Rower.MultipleObjectsReturned:
            return (0,'There is more than one user with that email address')
            
    if count_club_members(team.manager)+count_invites(team.manager) <= r.clubsize:
        codes = [i.code for i in TeamInvite.objects.all()]
        code = uuid.uuid4().hex[:10].upper()
        # prevent duplicates
        while code in codes:
            code = uuid.uuid4().hex[:10].upper()

        invite = TeamInvite(team=team,code=code,user=user,email=email)
        invite.save()
        return (invite.id,'Invitation created')
        
        
    else:
        return (0,'You are at your club size limit')

    return (0,'Nothing done')

def revoke_request(user,id):
    try:
        rekwest = TeamRequest.objects.get(id=id)
    except TeamRequest.DoesNotExist:
        return (0,'The request is invalid')

    t = rekwest.team

    if rekwest.user==user:
        rekwest.delete()
        return (1,'Request revoked')
    else:
        return (0,'You are not the requestor')

def revoke_invite(manager,id):
    try:
        invite = TeamInvite.objects.get(id=id)
    except TeamInvite.DoesNotExist:
        return (0,'The invitation is invalid')

    if invite.team.manager==manager:
        invite.delete()
        return (1,'Invitation revoked')
    else:
        return (0,'You are not the team manager')
    
def reject_request(manager,id):
    try:
        rekwest = TeamRequest.objects.get(id=id)
    except TeamRequest.DoesNotExist:
        return (0,'The request is invalid')

    if rekwest.team.manager==manager:
        send_request_reject_email(rekwest)
        rekwest.delete()
        return (1,'Request rejected')
    else:
        return (0,'You are not the manager for this request')

    
def reject_invitation(user,id):
    try:
        invite = TeamInvite.objects.get(id=id)
    except TeamInvite.DoesNotExist:
        return (0,'The invitation is invalid')

    if invite.user==user:
        send_invite_reject_email(invite)
        invite.delete()
        return (1,'Invitation rejected')
    else:
        return (0,'This request was not for you')


def send_invite_email(id):
    try:
        invitation = TeamInvite.objects.get(id=id)
    except TeamInvite.DoesNotExist:
        return (0,'Invitation doesn not exist')
        
    if invitation.user:
        email = invitation.user.email
        name = invitation.user.first_name + " " + invitation.user.last_name
    else:
        email = invitation.email
        name = ''
        
    code = invitation.code
    teamname = invitation.team.name
    manager = invitation.team.manager.first_name+' '+invitation.team.manager.last_name

    if settings.DEBUG:
        res = handle_sendemail_invite.delay(email,name,code,teamname,manager)
    else:
        res = queuehigh.enqueue(handle_sendemail_invite,
	                        email,name,code,teamname,manager)

    return (1,'Invitation email sent')

def send_team_delete_mail(t,rower):
    u = rower.user
    teamname = t.name
    email = u.email
    name = u.first_name+' '+u.last_name
    manager = t.manager.first_name+' '+t.manager.last_name
    if settings.DEBUG:
        res = handle_sendemail_team_removed.delay(email,name,teamname,manager)
    else:
        res = queuehigh.enqueue(handle_sendemail_team_removed,
	                        email,name,teamname,manager)

    return (1,'Team delete email sent')

def send_email_member_dropped(teamid,rower):
    t = Team.objects.get(id=teamid)
    u = rower.user
    teamname = t.name
    email = u.email
    name = u.first_name+' '+u.last_name
    manager = t.manager.first_name+' '+t.manager.last_name

    if settings.DEBUG:
        res = handle_sendemail_member_dropped.delay(email,name,teamname,manager)
    else:
        res = queuehigh.enqueue(handle_sendemail_member_dropped,
	                        email,name,teamname,manager)

    return (1,'Member dropped email sent')
    

def send_request_accept_email(rekwest):
    id = rekwest.id
    email = rekwest.user.email
    teamname = rekwest.team.name
    name = rekwest.user.first_name+' '+rekwest.user.last_name
    manager = rekwest.team.manager.first_name+' '+rekwest.team.manager.last_name
    
    if settings.DEBUG:
        res = handle_sendemail_request_accept.delay(email,name,teamname,manager)
    else:
        res = queuehigh.enqueue(handle_sendemail_request_accept,
	                        email,name,teamname,manager)

    return (1,'Invitation email sent')
    

def send_request_reject_email(rekwest):
    id = rekwest.id
    teamname = rekwest.team.name
    email = rekwest.user.email
    name = rekwest.user.first_name+' '+rekwest.user.last_name
    manager = rekwest.team.manager.first_name+' '+rekwest.team.manager.last_name
    
    if settings.DEBUG:
        res = handle_sendemail_request_reject.delay(email,name,teamname,manager)
    else:
        res = queuehigh.enqueue(handle_sendemail_request_reject,
	                        email,name,teamname,manager)

    return (1,'Invitation email sent')


def send_invite_reject_email(invitation):
    id = invitation.id
    email = invitation.team.manager.email
    if invitation.user:
        name = invitation.user.first_name+' '+invitation.user.last_name
    else:
        name = invitation.email

    teamname = invitation.team.name
    manager = invitation.team.manager.first_name+' '+invitation.team.manager.last_name

    if settings.DEBUG:
        res = handle_sendemail_invite_reject.delay(email,name,teamname,manager)
    else:
        res = queuehigh.enqueue(handle_sendemail_invite_reject,
	                        email,name,teamname,manager)

    return (1,'Invitation email sent')


def send_invite_accept_email(invitation):
    id = invitation.id
    email = invitation.team.manager.email
    if invitation.user:
        name = invitation.user.first_name+' '+invitation.user.last_name
    else:
        name = invitation.email

    teamname = invitation.team.name
    manager = invitation.team.manager.first_name+' '+invitation.team.manager.last_name

    if settings.DEBUG:
        res = handle_sendemail_invite_accept.delay(email,name,teamname,manager)
    else:
        res = queuehigh.enqueue(handle_sendemail_invite_accept,
	                        email,name,teamname,manager)

    return (1,'Invitation email sent')



def send_request_email(rekwest):
    email = rekwest.team.manager.email
    id = rekwest.id
    name = rekwest.team.manager.first_name + " " + rekwest.team.manager.last_name
    code = rekwest.code
    teamname = rekwest.team.name
    requestor = rekwest.user.first_name+' '+rekwest.user.last_name

    if settings.DEBUG:
        res = handle_sendemail_request.delay(email,name,code,teamname,
                                             requestor,id)
    else:
        res = queuehigh.enqueue(handle_sendemail_request,
	                        email,name,code,teamname,requestor,id)

    return (1,'Invitation email sent')

def process_request_code(manager,code):
    code = code.upper()
    
    try:
        rekwest = TeamRequest.objects.get(code=code)
    except TeamRequest.DoesNotExist:
        return (0,'The request has been revoked or the code is invalid')

    r = Rower.objects.get(user=rekwest.user)
    t = rekwest.team

    if rekwest.team.manager != manager:
        return (0,'You are not the manager of this team')

    result = add_member(t.id,r)
    send_request_accept_email(rekwest)
    rekwest.delete()
    return result

def process_invite_code(user,code):
    code = code.upper()
    try:
        invitation = TeamInvite.objects.get(code=code)
    except TeamInvite.DoesNotExist:
        return (0,'The invitation has expired or the code is invalid')

    r = Rower.objects.get(user=user)
    nu = datetime.date(timezone.now())
    if nu > invitation.issuedate+timedelta(days=inviteduration):
        revoke_invite(invitation.team.manager,invitation.id)
        return (0,'The invitation has expired')
    
    t = invitation.team
    result = add_member(t.id,r)
    send_invite_accept_email(invitation)
    invitation.delete()
    return result

def remove_expired_invites():
    issuedate = timezone.now()-timedelta(days=inviteduration)
    issuedate = datetime.date(issuedate)
    invitations = TeamInvite.objects.filter(issuedate__lt=issuedate)
    for i in invitations:
        revoke_invite(i.team.manager,i.id)

    return (1,'Expired invitations deleted')
