# -*- coding: utf-8 -*-

import gsxws
from datetime import date, timedelta

from django.conf import settings
from django.core.files import File
from django.core.mail import send_mail
from django.core.validators import validate_email
from django.utils.translation import ugettext as _

from django.core.management.base import BaseCommand

from django.db.models import F
from django.utils import timezone
from django.core.cache import cache

from servo.models.common import Configuration, Location, CsvTable, GsxAccount
from servo.models import Inventory, Order, PurchaseOrder, User


def send_table(sender, recipient, subject, table, send_empty=False):
    if send_empty is False and table.has_body() is False:
        return

    try:
        validate_email(sender)
        validate_email(recipient)
    except Exception:
        return

    config = Configuration.conf()
    host, port = Configuration.get_smtp_server()

    settings.EMAIL_HOST = host
    settings.EMAIL_PORT = int(port)
    settings.EMAIL_USE_TLS = config.get('smtp_ssl')
    settings.EMAIL_HOST_USER = config.get('smtp_user')
    settings.EMAIL_HOST_PASSWORD = config.get('smtp_password')

    send_mail(subject, unicode(table), sender, [recipient], fail_silently=False)


class Command(BaseCommand):
    help = "Runs Servo's periodic commands"

    def __init__(self, *args, **kwargs):
        super(Command, self).__init__(*args, **kwargs)
        uid = Configuration.conf('imap_act')
        self.mail_user = User.objects.get(pk=uid)
        self.mail_recipient = Configuration.notify_email_address()
        self.mail_sender = Configuration.get_default_sender(self.mail_user)

    def update_invoices(self):
        for a in GsxAccount.objects.all():
            try:
                a.default(self.mail_user)
                lookup = gsxws.Lookup(shipTo=a.ship_to, invoiceDate=date.today())
                invoices = lookup.invoices()
                for i in invoices:
                    details = gsxws.Lookup(invoiceID=i).invoice_details()
                    # @TODO: What about stock orders?
                    po = PurchaseOrder.objects.get(pk=details.purchaseOrderNumber)
                    po.invoice_id = i
                    po.invoice.save("%s.pdf" % i, File(open(details.invoiceData)))
            except Exception as e:
                raise e

    def update_warranty(self):
        pass

    def notify_aging_repairs(self):
        """
        Reports on cases that have been red for a day
        """
        now = timezone.now()
        limit = now - timedelta(days=1)

        for l in Location.objects.filter(enabled=True):
            table = CsvTable()
            subject = _(u"Repairs aging beyond limits at %s") % l.title
            table.addheader(['ORDER', 'ASSIGNED_TO', 'STATUS', 'DAYS_RED'])

            # "Aging" repairs are ones that have been red for at least a day
            orders = Order.objects.filter(location=l,
                                          state__lt=Order.STATE_CLOSED,
                                          status_limit_yellow__lt=limit)

            for o in orders:
                username = o.get_user_name() or _("Nobody")
                status_title = o.get_status_name() or _("No Status")
                days = (now - o.status_limit_yellow).days
                table.addrow([o.code, username, status_title, days])

            if Configuration.notify_location():
                recipient = l.manager.email if l.manager else l.email
                send_table(self.mail_sender, recipient, subject, table)
            if self.mail_recipient:
                send_table(self.mail_sender, self.mail_recipient, subject, table)

    def notify_stock_limits(self):
        """
        Notifies the correct parties of inventory items stocking status
        """
        subject = _(u"Products stocked below limit")

        for l in Location.objects.filter(enabled=True):
            out_of_stock = Inventory.objects.filter(
                location=l,
                amount_stocked__lt=F('amount_minimum')
            )

            table = CsvTable()
            table.addheader(['PRODUCT', 'MINIMUM', 'STOCKED'])

            for i in out_of_stock:
                table.addrow([i.product.code, i.amount_minimum, i.amount_stocked])

            if Configuration.notify_location():
                recipient = l.manager.email if l.manager else l.email
                send_table(self.mail_sender, recipient, subject, table)
            if self.mail_recipient:
                send_table(self.mail_sender, self.mail_recipient, subject, table)

    def update_counts(self):
        now = timezone.now()
        orders = Order.objects.filter(state__lt=Order.STATE_CLOSED)
        green = orders.filter(status_limit_green__gte=now)
        cache.set('green_order_count', green.count())
        yellow = orders.filter(status_limit_yellow__gte=now)
        cache.set('yellow_order_count', yellow.count())
        red = orders.filter(status_limit_yellow__lte=now)
        cache.set('red_order_count', red.count())

    def handle(self, *args, **options):
        #self.update_invoices()
        self.update_counts()
        self.notify_aging_repairs()
        self.notify_stock_limits()