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

from jinja2 import Template
from mailthon.postman import Postman
from mailthon import email
from mailthon.middleware import TLS, Auth
from collections import OrderedDict
from threading import Thread
import twilio
from twilio.rest import TwilioRestClient

import csv


class Postie(object):

    def __init__(self, args):
        self.args = args
        self.template = self.args.template
        self.csv = self.args.csv
        self.sender = self.args.sender
        self.subject = self.args.subject
        self.server = self.args.server
        self.port = self.args.port
        self.username = self.args.user
        self.password = self.args.password
        self.token = self.args.token
        self.sid = self.args.sid

    def init_mailthon(self):
        self.postman = Postman(
            host=self.server,
            port=self.port,
            middlewares=[
                TLS(force=True),
                Auth(username=self.username, password=self.password)
            ],
        )

    def init_twilio(self):
        self.client = TwilioRestClient(self.sid, self.token)

    @property
    def csv_content(self):
        """
        Read the csv file and return a list of rows.
        """
        with open(self.csv, 'rb') as fp:
            reader = csv.reader(fp)
            content = [item for item in reader]
        return content

    @property
    def dict_template(self):
        """
        Return an ordered dict with all the headers from csv file.
        """
        headers = self.csv_content[0]
        template_var_list = [each.strip() for each in headers][1:]
        return OrderedDict.fromkeys(template_var_list)

    def validate_header(self, mode):
        """
        Check is the first column of csv file contains email or phone number.
        """
        headers = self.csv_content[0]
        email_header = headers[0] if headers[0].lower() == mode else None
        if email_header is None:
            print "First column needs to have %s" % mode

    def render_template(self, **kwargs):
        """
        Render message template with Jinja 2 Engine
        """
        with open(self.template, 'rb') as fp:
            template = Template(fp.read().strip())
        return template.render(**kwargs)

    def send_async_email(self, envelope):
        self.postman.send(envelope)

    def send_async_sms(self, msg, to, from_):
        try:
            self.client.messages.create(body=msg,
                                        to=to,
                                        from_=from_)
        except twilio.TwilioRestException as e:
            print e

    def construct_msg(self, arg_list):
        """
        Insert the keyword values from csv file to the template.
        """
        template_kwargs = self.dict_template
        for i, key in enumerate(template_kwargs):
            template_kwargs[key] = arg_list[i + 1].strip()
        return self.render_template(**template_kwargs)

    def send_sms(self):
        content = self.csv_content[1:]
        for row in content:
            msg = self.construct_msg(row)
            thr = Thread(
                target=self.send_async_sms, args=[msg, row[0], self.sender])
            thr.start()
        return thr

    def send_emails(self):
        content = self.csv_content[1:]
        for row in content:
            envelope = email(
                sender=self.sender,
                receivers=[row[0]],
                subject=self.subject,
                content=self.construct_msg(row))
            # Spawn a thread for each email delivery
            thr = Thread(target=self.send_async_email, args=[envelope])
            thr.start()
        return thr

    def run(self):
        if self.token and self.sid is not None:
            print "Sending SMS using Twilo..."
            self.init_twilio()
            self.send_sms()
            print "Done sending text messages!"
        elif self.username and self.password is not None:
            print "Sending Emails..."
            self.init_mailthon()
            self.send_emails()
            print "Done sending emails!"
        else:
            print "Run postie --help for usage information"