from celery import Celery,app
import os
import time
import gc
import gzip
import shutil
import numpy as np

import rowingdata
from rowingdata import main as rmain
from rowingdata import rowingdata as rdata
import rowingdata
from async_messages import message_user,messages

from matplotlib.backends.backend_agg import FigureCanvas
#from matplotlib.backends.backend_cairo import FigureCanvasCairo as FigureCanvas
import matplotlib.pyplot as plt
from matplotlib import figure

import stravalib
import pandas as pd

from django_rq import job

from utils import serialize_list,deserialize_list

from rowers.dataprepnodjango import update_strokedata
from rowers.dataprepnodjango import new_workout_from_file
from rowers.dataprepnodjango import getsmallrowdata_db

from django.core.mail import send_mail, BadHeaderError,EmailMessage


import datautils
import utils

# testing task
@app.task
def add(x, y):
    return x + y

# create workout
@app.task
def handle_new_workout_from_file(r,f2,
                          workouttype='rower',
                          title='Workout',
                          makeprivate=False,
                          notes=''):
    return new_workout_from_file(r,f2,workouttype,
                                 title,makeprivate,notes)

# send email when a breakthrough workout is uploaded
@app.task
def handle_sendemail_breakthrough(workoutid,useremail,
                                  userfirstname,userlastname,
                                  btvalues = pd.DataFrame().to_json()):

    # send email with attachment
    subject = "A breakthrough workout on rowsandall.com"
    message = "Dear "+userfirstname+",\n"
    message += "Congratulations! Your recent workout has been analyzed"
    message += " by Rowsandall.com and it appears your fitness,"
    message += " as measured by Critical Power, has improved!"
    message += " Critical Power (CP) is the power that you can "
    message += "sustain for a given duration. For more, see this "
    message += " article in the analytics blog:\n\n"
    message += " http://analytics.rowsandall.com/2017/06/17/how-do-we-calculate-critical-power/ \n\n"
    message += "Link to the workout http://rowsandall.com/rowers/workout/"
    message += str(workoutid)
    message +="/edit\n\n"
    message +="To add the workout to your Ranking workouts and see the updated CP plot, click the following link:\n"
    message += "http://rowsandall.com/rowers/workout/"
    message += str(workoutid)
    message += "/updatecp\n\n"

    btvalues = pd.read_json(btvalues)
    btvalues.sort_values('delta',axis=0,inplace=True)
    
    if not btvalues.empty:
        message += "These were the breakthrough values:\n" 
        for t in btvalues.itertuples():
            delta = t.delta
            cpvalue = t.cpvalues
            pwr = t.pwr

            message += "Time: {delta} seconds\n".format(
                delta=delta
                )
            message += "New: {cpvalue:.0f} Watt\n".format(
                cpvalue=cpvalue
                )
            message += "Old: {pwr:.0f} Watt\n\n".format(
                pwr=pwr
                )

        
    message += "To opt out of these email notifications, deselect the checkbox on your Profile page under Account Information.\n\n"

    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [useremail])
			 

    res = email.send()

    # remove tcx file
    return 1


# send email to me when an unrecognized file is uploaded
@app.task
def handle_sendemail_unrecognized(unrecognizedfile,useremail):

    # send email with attachment
    fullemail = 'roosendaalsander@gmail.com'
    subject = "Unrecognized file from Rowsandall.com"
    message = "Dear Sander,\n\n"
    message += "Please find attached a file that someone tried to upload to rowsandall.com. The file was not recognized as a valid file type.\n\n"
    message += "User Email "+useremail+"\n\n"
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    email.attach_file(unrecognizedfile)
    
    res = email.send()

    # remove tcx file
    os.remove(unrecognizedfile)
    return 1

    
# Send email with TCX attachment
@app.task
def handle_sendemailtcx(first_name,last_name,email,tcxfile):

    # send email with attachment
    fullemail = first_name + " " + last_name + " " + "<" + email + ">"
    subject = "File from Rowsandall.com"
    message = "Dear "+first_name+",\n\n"
    message += "Please find attached the requested file for your workout.\n\n"
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    email.attach_file(tcxfile)
    
    res = email.send()

    # remove tcx file
    os.remove(tcxfile)
    return 1

@app.task
def handle_zip_file(emailfrom,subject,file):
    message = "... zip processing ... "
    email = EmailMessage(subject,message,
                         emailfrom,
                         ['workouts@rowsandall.com'])
    email.attach_file(file)
    res = email.send()
    time.sleep(60)
    return 1

# Send email with CSV attachment
@app.task
def handle_sendemailcsv(first_name,last_name,email,csvfile):

    # send email with attachment
    fullemail = first_name + " " + last_name + " " + "<" + email + ">"
    subject = "File from Rowsandall.com"
    message = "Dear "+first_name+",\n\n"
    message += "Please find attached the requested file for your workout.\n\n"
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    if os.path.isfile(csvfile):
        email.attach_file(csvfile)
    else:
        csvfile2 = csvfile
        with gzip.open(csvfile+'.gz','rb') as f_in, open(csvfile2,'wb') as f_out:
            shutil.copyfileobj(f_in, f_out)
            
        email.attach_file(csvfile2)
        os.remove(csvfile2)
        
    res = email.send()

    return 1

# Calculate wind and stream corrections for OTW rowing
@app.task
def handle_otwsetpower(f1,boattype,weightvalue,
                       first_name,last_name,email,workoutid,ps=[1,1,1,1],
                       ratio=1.0,
                       debug=False):
    try:
        rowdata = rdata(f1)
    except IOError:
        try:
            rowdata = rdata(f1+'.csv')
        except IOError:
            rowdata = rdata(f1+'.gz')
            
    weightvalue = float(weightvalue)

    # do something with boat type
    boatfile = {
	'1x':'static/rigging/1x.txt',
	'2x':'static/rigging/2x.txt',
	'2-':'static/rigging/2-.txt',
	'4x':'static/rigging/4x.txt',
	'4-':'static/rigging/4-.txt',
	'8+':'static/rigging/8+.txt',
	}
    try:
	rg = rowingdata.getrigging(boatfile[boattype])
    except KeyError:
	rg = rowingdata.getrigging('static/rigging/1x.txt')

    # do calculation, but do not overwrite NK Empower Power data
    powermeasured = False
    try:
        w = rowdata.df['wash']
        if w.mean() != 0:
            powermeasured = True
    except KeyError:
        pass

    rowdata.otw_setpower_silent(skiprows=5,mc=weightvalue,rg=rg,
                                powermeasured=powermeasured)

    # save data
    rowdata.write_csv(f1,gzip=True)
    update_strokedata(workoutid,rowdata.df,debug=debug)

    totaltime = rowdata.df['TimeStamp (sec)'].max()-rowdata.df['TimeStamp (sec)'].min()
    try:
        totaltime = totaltime+rowdata.df.ix[0,' ElapsedTime (sec)']
    except KeyError:
        pass
    df = getsmallrowdata_db(['power','workoutid','time'],ids=[workoutid])
    thesecs = totaltime
    maxt = 1.05*thesecs
    logarr = datautils.getlogarr(maxt)
    dfgrouped = df.groupby(['workoutid'])
    delta,cpvalues,avgpower = datautils.getcp(dfgrouped,logarr)
    
    
    #delta,cpvalues,avgpower = datautils.getsinglecp(rowdata.df)
    res,btvalues =  utils.isbreakthrough(delta,cpvalues,ps[0],ps[1],ps[2],ps[3],ratio)
    if res:
        handle_sendemail_breakthrough(workoutid,email,
                                      first_name,
                                      last_name,btvalues=btvalues.to_json())

    # send email
    fullemail = first_name + " " + last_name + " " + "<" + email + ">"
    subject = "Your Rowsandall OTW calculations are ready"
    message = "Dear "+first_name+",\n\n"
    message += "Your Rowsandall OTW calculations are ready.\n"
    message += "Thank you for using rowsandall.com.\n\n"
    message += "Rowsandall OTW calculations have not been fully implemented yet.\n"
    message += "We are now running an experimental version for debugging purposes. \n"
    message += "Your wind/stream corrected plot is available here: http://rowsandall.com/rowers/workout/"
    message += str(workoutid)
    message +="/interactiveotwplot\n\n"
    message += "Please report any bugs/inconsistencies/unexpected results at rowsandall.slack.com or by reply to this email.\n\n"
    message += "Best Regards, The Rowsandall Physics Department."

    send_mail(subject, message,
	      'Rowsandall Physics Department <info@rowsandall.com>',
	      [fullemail])

    return 1

# This function generates all the static (PNG image) plots
@app.task
def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename):

    hrmax  = hrdata['hrmax']
    hrut2  = hrdata['hrut2']
    hrut1  = hrdata['hrut1']
    hrat  = hrdata['hrat']
    hrtr  = hrdata['hrtr']
    hran  = hrdata['hran']
    ftp = hrdata['ftp']
    powerzones = deserialize_list(hrdata['powerzones'])
    powerperc = np.array(deserialize_list(hrdata['powerperc'])).astype(int)
    
    rr = rowingdata.rower(hrmax=hrmax,hrut2=hrut2,
			  hrut1=hrut1,hrat=hrat,
			  hrtr=hrtr,hran=hran,
                          ftp=ftp,powerperc=powerperc,
                          powerzones=powerzones)
    try:
        row = rdata(f2,rower=rr)
    except IOError:
        row = rdata(f2+'.gz',rower=rr)


    haspower = row.df[' Power (watts)'].mean() > 50
        
    nr_rows = len(row.df)
    if (plotnr in [1,2,4,5,8,11,9,12]) and (nr_rows > 1200):
	bin = int(nr_rows/1200.)
	df = row.df.groupby(lambda x:x/bin).mean()
	row.df = df
    nr_rows = len(row.df)
    if (plotnr==1):
	fig1 = row.get_timeplot_erg(t)
    elif (plotnr==2):
	fig1 = row.get_metersplot_erg(t)
    elif (plotnr==3):
	fig1 = row.get_piechart(t)
    elif (plotnr==4):
        if haspower:
            fig1 = row.get_timeplot_otwempower(t)
        else:
	    fig1 = row.get_timeplot_otw(t)
    elif (plotnr==5):
        if haspower:
            fig1 = row.get_metersplot_otwempower(t)
        else:
	    fig1 = row.get_metersplot_otw(t)
    elif (plotnr==6):
	fig1 = row.get_piechart(t)
    elif (plotnr==7) or (plotnr==10):
	fig1 = row.get_metersplot_erg2(t)
    elif (plotnr==8) or (plotnr==11):
	fig1 = row.get_timeplot_erg2(t)
    elif (plotnr==9) or (plotnr==12):
	fig1 = row.get_time_otwpower(t)
    elif (plotnr==13) or (plotnr==16):
	fig1 = row.get_power_piechart(t)

    canvas = FigureCanvas(fig1)

    #    plt.savefig('static/plots/'+imagename,format='png')
    canvas.print_figure('static/plots/'+imagename)
    # plt.imsave(fname='static/plots/'+imagename)
    plt.close(fig1)
    fig1.clf()
    gc.collect()

    return imagename

# Team related remote tasks

@app.task
def handle_sendemail_invite(email,name,code,teamname,manager):
    fullemail = name+' <'+email+'>'
    subject = 'Invitation to join team '+teamname
    message = 'Dear '+name+',\n\n'
    message += manager+' is inviting you to join his team '+teamname
    message += ' on rowsandall.com\n\n'
    message += 'By accepting the invite, you will have access to your'
    message += " team's workouts on rowsandall.com and your workouts will "
    message += " be visible to "
    message += "the members of the team.\n\n"
    message += 'If you already have an account on rowsandall.com, you can login to the site and you will find the invitation here on the Teams page:\n'
    message += ' https://rowsandall.com/rowers/me/teams \n\n'
    message += 'You can also click the direct link: \n'
    message += 'https://rowsandall.com/rowers/me/invitation/'+code+' \n\n'
    message += 'If you are not yet registered to rowsandall.com, '
    message += 'you can register for free at https://rowsandall.com/rowers/register\n'
    message += 'After you set up your account, you can use the direct link: '
    message += 'https://rowsandall.com/rowers/me/invitation/'+code+' \n\n'

    message += 'You can also manually accept your team membership with the code.\n'
    message += 'You will need to do this if you registered under a different email address than this one.\n'
    message += 'Code: '+code+'\n'
    message += 'Link to manually accept your team membership: '
    message += 'https://rowsandall.com/rowers/me/invitation\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1

@app.task
def handle_sendemailnewresponse(first_name,last_name,
                                email,
                                commenter_first_name,
                                commenter_last_name,
                                comment,
                                workoutname,workoutid,commentid):
    fullemail = first_name+' '+last_name+' <'+email+'>'
    subject = 'New comment on workout '+workoutname
    message = 'Dear '+first_name+',\n\n'
    message += commenter_first_name+' '+commenter_last_name
    message += ' has written a new comment on the workout '
    message += workoutname+'\n\n'
    message += comment
    message += '\n\n'
    message += 'You can read the comment here:\n'
    message += 'https://rowsandall.com/rowers/workout/'+str(workoutid)+'/comment'
    message += '\n\n'
    message += 'You are receiving this email because you are subscribed '
    message += 'to comments on this workout. To unsubscribe, follow this link:\n'
    message += 'https://rowsandall.com/rowers/workout/'+str(workoutid)+'/unsubscribe'

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1
    
@app.task
def handle_sendemailnewcomment(first_name,
			       last_name,
			       email,
                               commenter_first_name,
                               commenter_last_name,
                               comment,workoutname,
                               workoutid):
    fullemail = first_name+' '+last_name+' <'+email+'>'
    subject = 'New comment on workout '+workoutname
    message = 'Dear '+first_name+',\n\n'
    message += commenter_first_name+' '+commenter_last_name
    message += ' has written a new comment on your workout '
    message += workoutname+'\n\n'
    message += comment
    message += '\n\n'
    message += 'You can read the comment here:\n'
    message += 'https://rowsandall.com/rowers/workout/'+str(workoutid)+'/comment'

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1
    

@app.task
def handle_sendemail_request(email,name,code,teamname,requestor,id):
    fullemail = name+' <'+email+'>'
    subject = 'Request to join team '+teamname
    message = 'Dear '+name+',\n\n'
    message += requestor+' is requesting admission to your team '+teamname
    message += ' on rowsandall.com\n\n'
    message += 'Click the direct link to accept: \n'
    message += 'https://rowsandall.com/rowers/me/request/'+code+' \n\n'
    message += 'Click the following link to reject the request: \n'
    message += 'https://rowsandall.com/rowers/me/request/'+str(id)+' \n\n'
    message += 'You can find all pending requests on your team management page:\n'
    message += 'https://rowsandall.com/rowers/me/teams\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1

@app.task
def handle_sendemail_request_accept(email,name,teamname,managername):
    fullemail = name+' <'+email+'>'
    subject = 'Welcome to '+teamname
    message = 'Dear '+name+',\n\n'
    message += managername
    message += ' has accepted your request to be part of the team '
    message += teamname
    message += '\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1

@app.task
def handle_sendemail_request_reject(email,name,teamname,managername):
    fullemail = name+' <'+email+'>'
    subject = 'Your application to '+teamname+' was rejected'
    message = 'Dear '+name+',\n\n'
    message += 'Unfortunately, '
    message += managername
    message += ' has rejected your request to be part of the team '
    message += teamname
    message += '\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1

@app.task
def handle_sendemail_member_dropped(email,name,teamname,managername):
    fullemail = name+' <'+email+'>'
    subject = 'You were removed from '+teamname
    message = 'Dear '+name+',\n\n'
    message += 'Unfortunately, '
    message += managername
    message += ' has removed you from the team '
    message += teamname
    message += '\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1

@app.task
def handle_sendemail_team_removed(email,name,teamname,managername):
    fullemail = name+' <'+email+'>'
    subject = 'Team '+teamname+' was deleted'
    message = 'Dear '+name+',\n\n'
    message += managername
    message += ' has decided to delete the team '
    message += teamname
    message += '\n\n'
    message += 'The '+teamname+' tag has been removed from all your '
    message += 'workouts on rowsandall.com.\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1

@app.task
def handle_sendemail_invite_reject(email,name,teamname,managername):
    fullemail = managername+' <'+email+'>'
    subject = 'Your invitation to '+name+' was rejected'
    message = 'Dear '+managername+',\n\n'
    message  += 'Unfortunately, '
    message += name
    message += ' has rejected your invitation to be part of the team '
    message += teamname
    message += '\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1

@app.task
def handle_sendemail_invite_accept(email,name,teamname,managername):
    fullemail = managername+' <'+email+'>'
    subject = 'Your invitation to '+name+' was accepted'
    message = 'Dear '+managername+',\n\n'
    message += name+' has accepted your invitation to be part of the team '+teamname+'\n\n'
    message += "Best Regards, the Rowsandall Team"

    email = EmailMessage(subject, message,
			 'Rowsandall <info@rowsandall.com>',
			 [fullemail])
			 

    res = email.send()

    return 1



# Another simple task for debugging purposes
def add2(x,y):
    return x+y
