from rowers.models import Alert, Condition, User, Rower, Workout
from rowers.teams import coach_getcoachees
from rowers.dataprep import getsmallrowdata_db,getrowdata_db
import datetime
## BASIC operations

# create alert
def create_alert(manager, rower, measured,period=7, emailalert=True,
                 reststrokes=False, workouttype='water',boattype='1x',
                 name='',**kwargs):

    # check if manager is coach of rower. If not return 0
    if manager.rower != rower:
        if rower not in coach_getcoachees(manager.rower):
            return 0,'You are not allowed to create this alert'

    m = Condition(
        metric = measured['metric'],
        value1 = measured['value1'],
        value2 = measured['value2'],
        condition=measured['condition']
        )

    m.save()

    alert = Alert(name=name,
                  manager=manager,
                  rower=rower,
                  measured=m,
                  reststrokes=reststrokes,
                  period=period,
                  emailalert=emailalert,
                  workouttype=workouttype,
                  boattype=boattype,
                  )

    alert.save()

    if 'filter' in kwargs:
        filters = kwargs['filter']
        for f in filters:
            if f['metric'] and f['condition']:
                m = Condition(
                    metric = f['metric'],
                    value1 = f['value1'],
                    value2 = f['value2'],
                    condition = f['condition']
                )

                m.save()

                alert.filter.add(m)


    return alert.id,'Your alert was created'



# update alert
def alert_add_filters(alert,filters):
    for f in alert.filter.all():
        alert.filter.remove(f)
        f.delete()

    for f in filters:
        metric = f['metric']
        value1 = f['value1']
        value2 = f['value2']
        condition = f['condition']

        if condition and metric and value1:
            m = Condition(
                metric = f['metric'],
                value1 = f['value1'],
                value2 = f['value2'],
                condition = f['condition']
            )

            m.save()

            alert.filter.add(m)

    return 1

# get alert stats
# nperiod = 0: current period, i.e. next_run - n days to today
# nperiod = 1: 1 period ago , i.e. next_run -2n days to next_run -n days
def alert_get_stats(alert,nperiod=0):
    # get strokes
    workstrokesonly = not alert.reststrokes
    startdate = (alert.next_run - datetime.timedelta(days=(nperiod+1)*alert.period-1))
    enddate = alert.next_run - datetime.timedelta(days=(nperiod)*alert.period)
    columns = [alert.measured.metric]

    for condition in alert.filter.all():
        columns += condition.metric

    workouts = Workout.objects.filter(date__gte=startdate,date__lte=enddate,user=alert.rower,
                                      workouttype=alert.workouttype,duplicate=False,
                                      boattype=alert.boattype)
    ids = [w.id for w in workouts]

    df = getsmallrowdata_db(columns,ids=ids,doclean=True,workstrokesonly=workstrokesonly)

    if df.empty:
        return {
            'workouts':workouts.count(),
            'startdate':startdate,
            'enddate':enddate,
            'nr_strokes':0,
            'nr_strokes_qualifying':0,
            'percentage':0,
            'nperiod':nperiod,
            'median': 0,
            'median_q': 0,
            'standard_dev': 0,
        }

    # check if filters are in columns list
    pdcolumns = set(df.columns)

    # drop strokes through filter
    if set(columns) <= pdcolumns:
        for condition in alert.filter.all():
            if condition.condition == '>':
                mask = df[condition.metric] > condition.value1
                df.loc[mask,alert.measured.metric] = np.nan
            elif condition.condition == '<':
                mask = df[condition.metric] < condition.value1
                df.loc[mask,alert.measured.metric] = np.nan
            elif condition.condition == 'between':
                mask = df[condition.metric] > condition.value1
                mask2 = df[condition.metric] < condition.value2
                df.loc[mask & mask2,alert.measured.metric] = np.nan
            elif condition.condition == '=':
                mask = df[condition.metric] == condition.value1
                df.loc[mask,alert.measured.metric] = np.nan

        df.dropna(inplace=True,axis=0)
    else:
        return {
            'workouts':workouts.count(),
            'startdate':startdate,
            'enddate':enddate,
            'nr_strokes':0,
            'nr_strokes_qualifying':0,
            'percentage':0,
            'nperiod':nperiod,
            'median': 0,
            'median_q': 0,
            'standard_dev': 0,
        }


    # count strokes
    nr_strokes = len(df)


    # count qualifying
    if alert.measured.condition == '>':
        mask = df[alert.measured.metric] > alert.measured.value1
        df2 = df[mask].copy()
    elif alert.measured.condition == '<':
        mask = df[alert.measured.metric] < alert.measured.value1
        df2 = df[mask].copy()
    elif alert.measured.condition == 'between':
        mask = df[alert.measured.metric] > alert.measured.value1
        mask2 = df[alert.measured.metric] < alert.measured.value2
        df2 = df[mask & mask2].copy()
    else:
        mask = df[alert.measured.metric] == alert.measured.value1
        df2 = df[mask].copy()

    nr_strokes_qualifying = len(df2)

    if nr_strokes > 0:
        percentage = int(100.*nr_strokes_qualifying/nr_strokes)
    else:
        percentage = 0

    median_q = df2[alert.measured.metric].median()
    median = df[alert.measured.metric].median()
    std = df[alert.measured.metric].std()

    return {
        'workouts':workouts.count(),
        'startdate':startdate,
        'enddate':enddate,
        'nr_strokes':nr_strokes,
        'nr_strokes_qualifying':nr_strokes_qualifying,
        'percentage': percentage,
        'nperiod':nperiod,
        'median':median,
        'median_q':median_q,
        'standard_dev':std,
    }

# run alert report

# check alert permission
def checkalertowner(alert,user):
    if alert.manager == user:
        return True
    if alert.rower.user == user:
        return True
    return False
