#!/srv/venv/bin/python

""" Process emails """
import sys
import os
PY3K = sys.version_info >= (3, 0)

import zipfile
import re
import time
from time import strftime

import requests
import json

import io

from django.core.management.base import BaseCommand
from django_mailbox.models import Message, MessageAttachment,Mailbox
from django.urls import reverse
from django.conf import settings

from django.utils import timezone
from rowers.models import Workout, Rower

from rowingdata import rower as rrower
from rowingdata import rowingdata as rrdata

import rowers.uploads as uploads
from rowers.mailprocessing import make_new_workout_from_email, send_confirm
import rowers.polarstuff as polarstuff
import rowers.c2stuff as c2stuff
import rowers.stravastuff as stravastuff
from rowers.opaque import encoder

from rowers.models import User,VirtualRace,Workout
from rowers.plannedsessions import email_submit_race



# If you find a solution that does not need the two paths, please comment!
sys.path.append('$path_to_root_of_project$')
sys.path.append('$path_to_root_of_project$/$project_name$')

os.environ['DJANGO_SETTINGS_MODULE'] = '$project_name$.settings'

if not getattr(__builtins__, "WindowsError", None):
    class WindowsError(OSError): pass

def rdata(file_obj, rower=rrower()):
    """ Read rowing data file and return 0 if file doesn't exist"""
    try:
        result = rrdata(file_obj, rower=rower)
    except IOError:
        result = 0

    return result

def processattachment(rower, fileobj, title, uploadoptions,testing=False):
    try:
        filename = fileobj.name
#        filename = os.path.abspath(fileobj.name)
    except AttributeError:
        filename = fileobj[6:]
        if testing:
            print('Attribute Error', filename)


    # test if file exists and is not empty
    try:
        with io.open('media/'+filename,'rb') as fop:
            line = fop.readline()
    except (IOError, UnicodeEncodeError):
        if testing:
            print('IOError',filename,'media/'+filename)
        return 0

    if testing:
        print('Creating workout from email')

    # set user
    if rower.user.is_staff and 'username' in uploadoptions:
        users = User.objects.filter(username=uploadoptions['username'])
        if len(users)==1:
            therower = users[0].rower
        elif uploadoptions['username'] == '':
            therower = rower
        else:
            return 0
    else:
        therower = rower


    uploadoptions['secret'] = settings.UPLOAD_SERVICE_SECRET
    uploadoptions['user'] = therower.user.id
    uploadoptions['file'] = 'media/'+filename
    uploadoptions['title'] = title

    url = settings.UPLOAD_SERVICE_URL
    if not testing:
        response = requests.post(url,data=uploadoptions)
        # print("Upload response status code",response.status_code, response.json())
        if response.status_code == 200:
            response_json = response.json()
            workoutid = [int(response_json['id'])]
        else:
            workoutid = [0]

    # this is ugly and needs to be done better
    if testing:
        workoutid = [
            make_new_workout_from_email(therower, filename, title,testing=testing)
            ]
        if workoutid[0] and uploadoptions and not 'error' in uploadoptions:
            workout = Workout.objects.get(id=workoutid[0])
            uploads.make_private(workout, uploadoptions)
            uploads.set_workouttype(workout, uploadoptions)
            uploads.do_sync(workout, uploadoptions)


    if 'raceid' in uploadoptions and workoutid[0] and rower.user.is_staff:
        if testing and workoutid[0]:
            w = Workout.objects.get(id = workoutid[0])
            w.startdatetime = timezone.now()
            w.date = timezone.now().date()
            w.save()
        try:
            race = VirtualRace.objects.get(id=uploadoptions['raceid'])
            if race.manager == rower.user:
                result = email_submit_race(therower,race,workoutid[0])
        except VirtualRace.DoesNotExist:
            pass

    if testing:
        print('Workout id = {workoutid}'.format(workoutid=workoutid))

    return workoutid

def get_from_address(message):

    from_address = message.from_address[0].lower()

    if message.encoded:
        body = message.text.splitlines()
    else:
        body = message.get_body().splitlines()

    try:
        first_line = body[0].lower()
    except IndexError:
        first_line = ''

    try:
        first_line = first_line.decode('utf-8')
    except AttributeError:
        pass

    if "quiske" in first_line:
        match = re.search(r'[\w\.-]+@[\w\.-]+', first_line)
        return match.group(0)

    return from_address


class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument(
            '--testing',
            action='store_true',
            dest='testing',
            default=False,
            help="Run in testing mode, don't send emails",
            )
        parser.add_argument(
            '--mailbox',
            action='store_true',
            dest='mailbox',
            default='workouts',
            help="Changing mailbox name",
            )

    """Run the Email processing command """
    def handle(self, *args, **options):
        if 'testing' in options:
            testing = options['testing']
        else:
            testing = False

        if 'mailbox' in options:
            workoutmailbox = Mailbox.objects.get(name=options['mailbox'])
        else:
            workoutmailbox = Mailbox.objects.get(name='workouts')

        if 'failedmailbox' in options:
            failedmailbox = Mailbox.objects.get(name=options['failedmailbox'])
        else:
            failedmailbox = Mailbox.objects.get(name='Failed')

        # Polar
        polar_available = polarstuff.get_polar_notifications()
        res = polarstuff.get_all_new_workouts(polar_available)

        # Concept2
        rowers = Rower.objects.filter(c2_auto_import=True).exclude(rowerplan='basic')
        for r in rowers:
            c2stuff.get_c2_workouts(r)


        messages = Message.objects.filter(mailbox_id = workoutmailbox.id)
        message_ids = [m.id for m in messages]
        attachments = MessageAttachment.objects.filter(
            message_id__in=message_ids
        )
        cntr = 0
        for attachment in attachments:
            filename, extension = os.path.splitext(attachment.document.name)
            extension = extension.lower()
#            extension = attachment.document.name[-3:].lower()
            try:
                message = Message.objects.get(id=attachment.message_id)
                if message.encoded:
#                if message.text:
                    body = "\n".join(message.text.splitlines())
                else:
                    body = message.get_body()

                uploadoptions = uploads.upload_options(body)

                from_address = get_from_address(message)

                name = message.subject
                # get a list of users
                # theusers = User.objects.filter(email=from_address)
                rowers = [
                    r for r in Rower.objects.all() if r.user.email.lower() == from_address
                ]
            except IOError:
                rowers = []
            except Message.DoesNotExist:
                attachment.delete()
            for rower in rowers:
                if 'zip' in extension:
                    zip_file = zipfile.ZipFile(attachment.document)
                    for id,filename in enumerate(zip_file.namelist()):
                        datafile = zip_file.extract(
                            filename, path='media/')
                        if id>0:
                            title = name+' ('+str(id+1)+')'
                        else:
                            title = name
                        workoutid = processattachment(
                            rower, datafile, title, uploadoptions,
                            testing=testing
                        )

                else:
                    # move attachment and make workout
                    if testing:
                        try:
                            print(name)
                        except UnicodeEncodeError:
                            print("Unicode Error")
                        try:
                            print(attachment.document)
                        except UnicodeEncodeError:
                            pass

                    workoutid = processattachment(
                        rower, attachment.document, name, uploadoptions,
                        testing=testing
                    )

            # We're done with the attachment. It can be deleted
            try:
                attachment.delete()
            except IOError:
                pass
            except WindowsError:
                if not testing:
                    time.sleep(2)
                try:
                    attachment.delete()
                except WindowsError:
                    pass
            except:
                message.mailbox = failedmailbox
                message.save()

            if message.attachments.exists() is False:
                # no attachments, so can be deleted
                message.delete()

        messages = Message.objects.all()
        for message in messages:
            if message.attachments.exists() is False:
                message.delete()

        # Strava
        rowers = Rower.objects.filter(strava_auto_import=True).exclude(rowerplan='basic')
        for r in rowers:
            stravastuff.get_strava_workouts(r)

        self.stdout.write(self.style.SUCCESS(
            'Successfully processed email attachments'))
