import sys
import json
import socket
import smtplib
import threading

from idb import log
from .core.db import sqlite

log.set_logging_prefix("alert_engine.alert")
_logger = log.get_logger("alert_engine.alert")
log.config_logging()

MAX_EMAIL_SEND_RETRIES = 3

SMTP_PORT = 25
SMTP_SSL_PORT = 465
SMTP_STARTTLS_PORT = 587
FROM_EMAIL = "alert@scalearc.com"


def sendmail(config, recipients, subject, body):
    _logger.info("Start Sending email to %s" %recipients)
    host = config['smtp_ip'][6:] if config['smtp_ip'].startswith('ssl://') else config['smtp_ip']
    port = int(config['smtp_port'])

    enc = 'no' if 'smtp_encryption' not in config else config['smtp_encryption'].lower()

    if enc == 'no':
        if config['smtp_ip'].startswith('ssl://'):
            enc = 'ssl'
        elif port == SMTP_SSL_PORT:
            enc = 'ssl'
        elif port == SMTP_STARTTLS_PORT:
            enc = 'starttls'

    retries = 0
    while retries < MAX_EMAIL_SEND_RETRIES:
        try:
            if enc in ['ssl', 'tls']:
                smtp = smtplib.SMTP_SSL(host, port)
            else:
                smtp = smtplib.SMTP(host, port)
            smtp.ehlo()

            if enc == 'starttls':
                smtp.starttls()
                smtp.ehlo()

            if config['smtp_user']:
                user = config['smtp_user']
                password = config['smtp_pass']
                smtp.login(user, password)
            else:
                user = 'ScaleArc Alerts <%s>' %FROM_EMAIL

            message = 'From: %s \r\nTo: %s\r\nSubject: %s\r\n\r\n%s' \
                        % (FROM_EMAIL, ','.join(recipients), subject, body)

            _logger.info("Message for sending email is %s" %message)
            smtp.sendmail(FROM_EMAIL, recipients, message)
            _logger.info('Email \'%s\' sent to %s' % (subject, recipients))
            smtp.close()
            break
        except Exception, ex:
            retries += 1
            _logger.error("Unable to send '%s': %s" % (subject, ex))

class alert(threading.Thread):
    def __init__(self, alertq):
        super(alert, self).__init__()
        self.alertq = alertq
        hostname = 'scalearc'
        try:
            hostname = socket.gethostname()
        except Exception as ex:
            _logger.error("Could not get hostname, using '%s'" % (hostname))
        self._footer = "This is a system generated email by alert_engine on host '%s'." % (hostname)
        self.titles = []

    def run(self):
        while True:
            channel, data = self.alertq.get()
            message = data.get('message', None)
            if not message:
                break

            self.alert_email(channel, data)

    def get_cluster_smtp_config(self, cid=None):
        columns = ['smtp_ip', 'smtp_port', 'smtp_encryption', 'smtp_user', 'smtp_pass', 'emailids', 'clusterid']
        condition = 'status=1'
        if cid:
            return sqlite.get(columns, 'lb_sendalert', condition, cid)

        smtp_config = []
        clusters = sqlite.get(['cluster_id'], 'lb_clusters_summary', condition)
        for c in clusters:
            conf = sqlite.get(columns, 'lb_sendalert', condition, c['cluster_id'])
            if len(conf):
                smtp_config += conf
        return smtp_config

    def get_cluster_name(self, cid):
        condition = 'status=1'
        r = sqlite.get(['clustername'], 'lb_clusters', condition, cid)
        if r and len(r):
            return r[0]['clustername']
        _logger.error("Cluster %d config doesn\'t appear correct. No cluster name found." % (cid))
        return ''

    def format_subject(self, channel, data):
        subject = 'ScaleArc Alert'
        tmp = data.get('subject', None)
        if tmp:
            return subject + ': ' + tmp
        if channel in self.titles:
            return subject + ': ' + self.titles[channel]
        return subject

    def format_email(self, channel, data):
        body = ''
        cid = data.get('cid', None)
        if cid:
            cname = self.get_cluster_name(cid)
            body += 'Cluster: %s\r\n' % cname

        message = data.get('message', None)
        body += message + "\r\n\r\n"
        body += self._footer 
        return body

    def alert_email(self, channel, data):
        cid = data.get('cid', None)
        smtp_config = self.get_cluster_smtp_config(cid)
 
        if not smtp_config or not len(smtp_config):
            _logger.info("No SMTP config for cid %d: %s" % (cid, data.get('subject', '')))
            return False

        subject = self.format_subject(channel, data)
        body = self.format_email(channel, data)

        already_sent = []
        for conf in smtp_config:
            recipients = [i for i in conf['emailids'].split(',') if i not in already_sent]
            if len(recipients):
                sendmail(conf, recipients, subject, body)
                already_sent += recipients

if __name__ == "__main__":
    args = sys.argv[1:]
    if len(args) != 1:
        print("Incorrect parameters passed '%s'" % (args))
        sys.exit(1)

    try:
        config = json.loads(args[0])
    except Exception as e:
        print("Error (%s) occurred while trying to decode request." % (e))
        sys.exit(1)

    try:
        recipients = config['email_ids'].split(',')
        config['smtp_ip'] = config['smtp_server']
        config['smtp_user'] = config['smtp_username']
        config['smtp_pass'] = config['smtp_password']

        sendmail(config, recipients, 'ScaleArc Alerts: Test Email', 'This is test mail from iDB, please ignore.')
    except Exception as e:
        print("Error occurred (%s)" % str(e))
        sys.exit(1)
