from django import template
from django.utils.safestring import mark_safe
from time import strftime
from django.utils import timezone
import dateutil.parser
import json
import math
import datetime
import re
register = template.Library()
from rowers.utils import calculate_age
from rowers.models import (
    course_length,WorkoutComment,
    TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle,
    Rower,Workout,SiteAnnouncement, TeamInvite, TeamRequest, CoachOffer,CoachRequest,
    VirtualRaceFollower,VirtualRace,
    )
from rowers.plannedsessions import (
    race_can_register, race_can_submit,race_rower_status
    )

from rowers import c2stuff, runkeeperstuff
from rowers.c2stuff import c2_open
from rowers.runkeeperstuff import runkeeper_open
from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember
from rowers.mytypes import (
    otwtypes,adaptivetypes,sexcategories,weightcategories,workouttypes,
    )
from rowers.utils import NoTokenError

import rowers.payments as payments


from rowers.opaque import encoder

import arrow

from django.utils.safestring import mark_safe
from django.utils.html import urlize as urlize_impl
from django.template.defaultfilters import stringfilter

from six import string_types

@register.filter
def isfollower(user,id):

    if user.is_anonymous:
        return True
    try:
        race = VirtualRace.objects.get(id=id)
    except VirtualRace.DoesNotExist:
        return False

    followers = VirtualRaceFollower.objects.filter(race=race,user=user)


    return followers.count()==0

@register.filter
def adaptive(s):
    u = s

    for e,v in adaptivetypes:
        if e.lower() == u.lower():
            u = v
            continue

    return u

@register.filter
def boatclass(s):
    u = s

    for e,v in workouttypes:
        if e.lower() == u.lower():
            u = v
            continue

    return u

@register.filter
def sex(s):
    u = s

    for e,v in sexcategories:
        if e.lower() == u.lower():
            u = v
            continue

    return u

@register.filter
def weight(s):
    u = s

    for e,v in weightcategories:
        if e.lower() == u.lower():
            u = v
            continue

    return u

@register.filter
def sigdig(value, digits = 3):
    try:
        order = int(math.floor(math.log10(math.fabs(value))))
    except (ValueError,TypeError):
        return value

    # return integers as is
    if value % 1 == 0:
        return value

    places = digits - order - 1
    if places > 0:
        fmtstr = "%%.%df" % (places)
    else:
        fmtstr = "%.0f"
    return fmtstr % (round(value, places))

@register.filter
def pickle(dc):
    s = dict()
    for key, value in dc.items():
        s[key] = value

    return s

@register.filter(is_safe=True, needs_autoescape=True)
@stringfilter
def urlshorten(value, limit,autoescape=None):
    return mark_safe(
        urlize_impl(
            value, trim_url_limit=int(limit),
            nofollow=True, autoescape=autoescape).replace('<a', '<a target="_blank"'))

@register.filter
def nogoals(user):
    targets = TrainingTarget.objects.filter(rowers=user.rower,
                                            date__gte=datetime.date.today())
    return len(targets)==0

@register.filter
def notfree(rower):
    return rower.rowerplan not in ['basic','freecoach']

def strfdelta(tdelta):
    minutes,seconds = divmod(tdelta.seconds,60)
    tenths = int(tdelta.microseconds/1e5)
    res = "{minutes:0>1}:{seconds:0>2}.{tenths:0>1}".format(
        minutes=minutes,
        seconds=seconds,
        tenths=tenths,
        )

    return res

from rowers.teams import rower_get_managers

@register.filter
def alertstatspercentage(list,i):
    alertstats = list[i-1]

    return alertstats["percentage"]

@register.filter
def alertstartdate(list,i):
    alertstats = list[i-1]

    return alertstats["startdate"]

@register.filter
def alertnperiod(list,i):
    alertstats = list[i-1]

    return alertstats["nperiod"]

@register.filter
def alertenddate(list,i):
    alertstats = list[i-1]

    return alertstats["enddate"]

@register.filter
def is_coach(rower,rowers):
    for r in rowers:
        if rower not in rower_get_managers(r):
            print(r,rower)
            return False

    return True

@register.filter
def waterpower(x,rower):
    if rower is not None:
        return int(x*(100-rower.otwslack)/100.)
    return int(x)

@register.filter
def round20(x):
    try:
        return int(20.*(1+int(int(x)/20)))
    except ValueError:
        return 20

@register.filter
def round100(x):
    try:
        return int(100.*(1+int(int(x)/100)))
    except ValueError:
        return 100

@register.filter
def majorticks(maxval):
    ticks = range(1+int(maxval/100.))
    newticks =[]
    for t in ticks:
        newticks.append(t*100)

    return newticks

@register.filter
def hrmajorticks(maxval,minval):
    ticks = range(int((maxval-minval)/20.)-1)
    newticks =[]
    for t in ticks:
        newticks.append(100+t*20)

    print(newticks)
    return newticks

def strfdeltah(tdelta):
    hours, rest = divmod(tdelta.seconds,3600)
    minutes,seconds = divmod(rest,60)
    tenths = int(tdelta.microseconds/1e5)
    res = "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format(
        hours=hours,
        minutes=minutes,
        seconds=seconds,
        tenths=tenths,
        )

    return res

def secondstotimestring(tdelta):
    hours, rest = divmod(tdelta,3600)
    minutes,seconds = divmod(rest,60)
    res = "{hours:0>2}:{minutes:0>2}:{seconds:0>2}".format(
        hours=hours,
        minutes=minutes,
        seconds=seconds,
        )

    return res

@register.filter
def existing_customer(user):
    if user.is_anonymous:
        return False
    else:
        return payments.is_existing_customer(user.rower)

@register.filter
def aantalcomments(workout):
    try:
        comments = WorkoutComment.objects.filter(workout=workout)
    except:
        return 0

    aantalcomments = len(comments)

    return aantalcomments

@register.filter
def encode(id):
    try:
        result = str(encoder.encode_hex(id))
    except TypeError:
        result = ''
    return result

@register.filter
def water(workout):
    try:
        return workout.workouttype in otwtypes
    except AttributeError:
        return False

@register.filter
def ddays(ddelta):
    return ddelta.days+1

@register.filter
def spacetohtml(t):
    return t.replace(" ","%20")

@register.filter
def durationprint(d,dstring):
    if (d == None):
        return d
    else:
        try:
            return d.strftime(dstring)[:-5]
        except AttributeError:
            return None

def getstartenddate(timeperiod):
    s,e = timeperiod.split('/')
    startdate = arrow.get(s).date()
    enddate = arrow.get(e).date()

    return startdate,enddate

@register.filter
def nextperiodend(timeperiod):
    startdate,enddate = getstartenddate(timeperiod)
    timedelta = enddate-startdate
    newstartdate = enddate+datetime.timedelta(days=1)
    newenddate = newstartdate+timedelta

    return newenddate.strftime("%Y-%m-%d")


@register.filter
def nextperiodstart(timeperiod):
    startdate,enddate = getstartenddate(timeperiod)
    timedelta = enddate-startdate
    newstartdate = enddate+datetime.timedelta(days=1)
    newenddate = newstartdate+timedelta

    return newstartdate.strftime("%Y-%m-%d")

@register.filter
def previousperiodend(timeperiod):
    startdate,enddate = getstartenddate(timeperiod)
    timedelta = enddate-startdate
    newenddate = startdate-datetime.timedelta(days=1)
    newstartdate = startdate-timedelta-datetime.timedelta(days=1)

    return newenddate.strftime("%Y-%m-%d")

@register.filter
def timedeltadays(timeperiod):
    startdate,enddate = getstartenddate(timeperiod)
    timedelta = enddate-startdate

    return timedelta.days+1

@register.filter
def previousperiodstart(timeperiod):
    startdate,enddate = getstartenddate(timeperiod)
    timedelta = enddate-startdate
    newenddate = startdate-datetime.timedelta(days=1)
    newstartdate = startdate-timedelta-datetime.timedelta(days=1)

    return newstartdate.strftime("%Y-%m-%d")

@register.filter
def paceprint(d):
    if (d == None):
        return d
    else:
        return strfdelta(d)

@register.filter
def deltatimeprint(d):
    if (d == None):
        return d
    else:
        return strfdeltah(d)

@register.filter
def c2userid(user):
    try:
        thetoken = c2_open(user)
    except NoTokenError:
        return 0

    c2userid = c2stuff.get_userid(thetoken)

    return c2userid

@register.filter
def currency(word):
    try:
        amount = float(word)
    except ValueError:
        return word

    return '{amount:.2f}'.format(amount=amount)

@register.filter
def rkuserid(user):
    try:
        thetoken = runkeeper_open(user)
    except NoTokenError:
        return 0

    rkuserid = runkeeperstuff.get_userid(thetoken)

    return rkuserid

@register.filter
def courselength(course):
    return course_length(course)

@register.filter(is_safe=True)
def jsdict(dict,key):
    s = dict.get(key)
    return mark_safe(json.dumps(s))



@register.filter
def lookup(dict, key):
    try:
        s = dict.get(key)
    except KeyError:
        return None

    if isinstance(s,string_types) and len(s) > 22:
        s = s[:22]
    return s

@register.filter
def lookuplong(dict, key):
    try:
        s = dict.get(key)
    except KeyError:
        return None

    return s

@register.filter
def ualookup(dict, key):
    s = dict.get(key)

    if key=='distance':
        s = int(float(s))

    if key=='duration':
        s = secondstotimestring(int(s))


    if key=='starttime':
        s = dateutil.parser.parse(s)

    return s

from rowers.models import PlannedSession
@register.filter
def is_session_manager(id,user):
    try:
        ps = PlannedSession.objects.get(id=id)
    except PlannedSession.DoesNotExist:
        return False

    return ps.manager == user


@register.filter
def may_edit(workout,request):
    mayedit = 0
    if request.user == workout.user.user:
        mayedit = True
    if is_workout_user(request.user,workout):
        mayedit = True

    return mayedit



@register.filter
def mayeditplan(obj,request):

    if obj is None:
        return False

    if hasattr(obj,'plan'):
        return mayeditplan(obj.plan,request)

    if hasattr(obj,'manager'):
        if obj.manager is not None:
            return request.user == obj.manager.user

    rr = Rower.objects.get(user=request.user)
    if is_coach_user(request.user,obj.rower) and rr.rowerplan not in ['basic','pro']:
        mayedit = True


    return mayedit


@register.filter(name='times')
def times(number):
    return range(number)

@register.simple_tag
def get_field_id(id,s,form):
    field_name = s+str(id)
    return form.__getitem__(field_name)

from rowers.models import Rower,Team,TrainingPlan,TrainingTarget


@register.filter
def is_promember(user):
    return ispromember(user)

@register.filter
def is_manager(user):
    r = Rower.objects.get(user=user)
    return 'coach' in r.rowerplan


@register.filter
def is_planmember(user):
    return isplanmember(user)

@register.filter
def get_age(r):
    return calculate_age(r.birthdate)


@register.filter
def user_teams(user):
    try:
        therower = Rower.objects.get(user=user)
        teams1 = therower.team.all()
        teams2 = Team.objects.filter(manager=user)
        teams = list(set(teams1).union(set(teams2)))
    except TypeError:
        teams = []

    return teams

@register.filter
def user_team1(user):
    try:
        therower = Rower.objects.get(user=user)
        teams1 = therower.team.all()
        teams2 = Team.objects.filter(manager=user)
        teams = list(set(teams1).union(set(teams2)))
    except TypeError:
        teams = []

    return teams[0].id

@register.filter
def announcements(request):
    announcements = SiteAnnouncement.objects.filter(
        expires__gte=datetime.date.today()).order_by(
            "-created",
            "-id"
            )

    return announcements[0:4]

@register.filter
def has_teams(user):
    try:
        therower = Rower.objects.get(user=user)
        teams1 = therower.team.all()
        teams2 = Team.objects.filter(manager=user)
        teams = list(set(teams1).union(set(teams2)))
        return True
    except TypeError:
        return False

    return False

@register.filter
def team_members(user):
    try:
        therower = Rower.objects.get(user=user)
        if therower.rowerplan == 'basic':
            return []
        teams = Team.objects.filter(manager=user)
        members = Rower.objects.filter(
            team__in=teams
        ).distinct().order_by(
            "user__last_name","user__first_name"
            ).exclude(rowerplan='freecoach')
        return [rower.user for rower in members]
    except TypeError:
        return []

    return []

@register.filter
def openactions(user):
    myteams = Team.objects.filter(manager=user)

    invites = TeamInvite.objects.filter(user=user).count()
    requests = TeamRequest.objects.filter(user=user).count()
    myrequests = TeamRequest.objects.filter(team__in=myteams).count()
    myinvites = TeamInvite.objects.filter(team__in=myteams).count()
    mycoachoffers = CoachOffer.objects.filter(coach=user.rower).count()
    coachoffers = CoachOffer.objects.filter(user=user).count()
    mycoachrequests = CoachRequest.objects.filter(user=user).count()
    coachrequests = CoachRequest.objects.filter(coach=user.rower).count()

    return invites+requests+myrequests+myinvites+mycoachoffers+coachoffers+mycoachrequests+coachrequests


@register.filter
def team_rowers(user):
    try:
        therower = Rower.objects.get(user=user)
        if therower.rowerplan == 'basic':
            return []
        teams = Team.objects.filter(manager=user)
        members = Rower.objects.filter(team__in=teams).distinct().order_by(
            "user__last_name","user__last_name"
            ).exclude(rowerplan='freecoach')
        return members
    except TypeError:
        return []

    return []

from rowers.teams import coach_getcoachees

@register.filter
def coach_rowers(user):
    if user.rower.rowerplan != 'freecoach':
        thelist = [user.rower]+[c for c in coach_getcoachees(user.rower)]
    else:
        thelist = [c for c in coach_getcoachees(user.rower)]
    return thelist


@register.filter
def verbosetimeperiod(timeperiod):
    table = {
        'today':'Today',
        'thisweek': 'This Week',
        'thismonth': 'This Month',
        'lastmonth': 'Last Month',
        'lastweek': 'Last Week',
        'nextweek': 'Next Week',
        'nextmonth': 'Next Month',
        }

    try:
        verbose = table[timeperiod]
    except KeyError:
        verbose = timeperiod

    return verbose

from datetime import date

@ register.filter
def future_date_only(the_date):
    if the_date > date.today():
        return the_date
    else:
        return None


@register.filter
def is_future_date(the_date):
    return the_date >= date.today()

@register.filter
def amount(value):
    vs = '{v}.00'.format(v=int(value))
    return vs



@register.filter
def date_dif(the_date):
    if the_date == date(1970,1,1):
        return 1
    if the_date:
        return the_date - date.today()
    else:
        return 1


@register.filter
def can_register(race,r):
    return race_can_register(r,race)

@register.filter
def can_submit(race,r):
    return race_can_submit(r,race)

@register.filter
def race_complete(race,r):
    is_complete,has_registered = race_rower_status(r,race)
    return is_complete

@register.filter
def past_not_registered(race,r):
    is_complete,has_registered = race_rower_status(r,race)
    return not has_registered

@register.filter
def future_registered(race,r):
    is_complete, has_registered = race_rower_status(r,race)
    is_open = race.evaluation_closure > timezone.now()
    return has_registered and not is_complete and is_open

@property
def is_past_due(self):
    return datetime.date.today() > self.date
@property
def is_not_past_due(self):
    return datetime.date.today() <= self.date

@register.filter
def is_closed(race):
    return race.evaluation_closure < timezone.now()

@register.filter
def is_final(race):
    return race.evaluation_closure < timezone.now()-datetime.timedelta(hours=1)

@register.filter
def userurl(path,member):
    pattern = re.compile('user\/\d+/')
    userstring = 'user/%s/' % member.id

    # remove team
    tpattern = re.compile('team\/\d+/')
    if tpattern.search(path) is not None:
        path = tpattern.sub('',path)

    if pattern.search(path) is not None:
        replaced = pattern.sub(userstring,path)
    else:
        replaced = path+userstring

    return replaced

@register.filter
def teamurl(path,team):
    pattern = re.compile('team\/\d+/')
    teamstring = 'team/%s/' % team.id

    # remove user
    upattern = re.compile('\/user\/\d+/')
    if upattern.search(path) is not None:
        path = upattern.sub('/',path)


    if pattern.search(path) is not None:
        replaced = pattern.sub(teamstring,path)
    else:
        replaced = path+teamstring


    return replaced

@register.filter
def timeurl(path,timestring):
    pattern = re.compile('\?when=w.*')
    timeurl = '?when=%s' % timestring
    replaced = ''

    if pattern.search(path) is not None:
        replaced = pattern.sub(timeurl,path)

    if not replaced:
        replaced = path+timeurl

    return replaced

@register.filter
def trainingplans(rower):
    today = datetime.date.today()
    plans = TrainingPlan.objects.filter(
        rowers=rower,
        status=True,
        startdate__lte=today,
        enddate__gte=today).order_by("-startdate")

    return plans

@register.filter
def mesomacroid(id):
    try:
        thismeso = TrainingMesoCycle.objects.get(id=id)
    except TrainingMesoCycle.DoesNotExist:
        return '0'

    theid = thismeso.plan.id

    return str(theid)

@register.filter
def micromesoid(id):
    try:
        thismicro = TrainingMicroCycle.objects.get(id=id)
    except TrainingMicroCycle.DoesNotExist:
        return '0'

    theid = thismicro.plan.id

    return str(theid)


@register.filter
def micromacroid(id):
    try:
        thismicro = TrainingMicroCycle.objects.get(id=id)
    except TrainingMicroCycle.DoesNotExist:
        return '0'

    theid = thismicro.plan.plan.id

    return str(theid)

@register.filter
def nextworkout(workout,user):
    if user.rower == workout.user:
        try:
            ws = Workout.objects.filter(
                startdatetime__gte=workout.startdatetime,
                user=workout.user
            ).order_by(
                "startdatetime"
            ).exclude(id=workout.id)
        except ValueError:
            return 0
    else:
        try:
            ws = Workout.objects.filter(
                startdatetime__gte=workout.startdatetime,
                user=workout.user,privacy='visible'
            ).order_by(
                "startdatetime"
            ).exclude(id=workout.id)
        except ValueError:
            return 0

    if ws:
        return encoder.encode_hex(ws[0].id)
    else:
        return 0



@register.filter
def previousworkout(workout,user):
    if user.rower == workout.user:
        try:
            ws = Workout.objects.filter(
                startdatetime__lte=workout.startdatetime,
                user=workout.user
            ).order_by(
                "-startdatetime"
            ).exclude(id=workout.id)
        except ValueError:
            return 0
    else:
        try:
            ws = Workout.objects.filter(
                startdatetime__lte=workout.startdatetime,
                user=workout.user,privacy='visible'
            ).order_by(
                "-startdatetime"
            ).exclude(id=workout.id)
        except ValueError:
            return 0


    if ws:
        return encoder.encode_hex(ws[0].id)
    else:
        return 0
