#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import re
import logging
import json
import datetime
import dateutil.parser
import direct_juggler.juggler as dj
import kazoo.client
logging.getLogger(kazoo.client.__name__).setLevel(logging.WARNING)

sys.path.insert(0, '/opt/downtime-db-utils')
import downtime_db_utils as utils

sys.path.insert(0, '/opt/check-db-availability')
import check_db_utils

SERVICE_NAME_WORKING = "downtime-db-notify.working"
SERVICE_NAME = "downtime-db.%s"
ALLDB_CONFIG_PATH = "/etc/yandex-direct/alldb-config.json"


def main():
    cur_dt = datetime.datetime.now()

    with open(ALLDB_CONFIG_PATH, "r") as fh:
        alldb_config = json.load(fh)['instances']

    utils.zkh.start()
    utils.get_lock()

    juggler_events = []
    host2instance = {}

    for instance in alldb_config:
        db_config = check_db_utils.get_db_config(alldb_config[instance], instance)
        if 'db_config_master_node' not in alldb_config[instance]:
            continue

        db_config_master = check_db_utils.get_db_config_data(
            db_config, alldb_config[instance]['db_config_master_node']
        )

        if db_config_master not in host2instance:
            host2instance[db_config_master] = []
        host2instance[db_config_master].append(instance)

    host2instance.update({
        host: []
        for host in utils.zkh.get_children(utils.ZK_LOCATION) if host != utils.LOCK_NAME and host not in host2instance
    })

    for host in host2instance:
        zk_path = "%s/%s" % (utils.ZK_LOCATION, host)
        instances = host2instance[host]
        event_sent = False

        if utils.zkh.exists(zk_path):
            downtimes = utils.parse_node(zk_path)

            last_ind = 0
            for downtime, info in downtimes:
                downtime_dt = dateutil.parser.parse(downtime)
                if downtime_dt - cur_dt < - datetime.timedelta(hours=1):
                    last_ind += 1
                    continue

                if downtime_dt - cur_dt <= datetime.timedelta(hours=2):
                    status = "CRIT"
                elif downtime_dt - cur_dt <= datetime.timedelta(hours=12):
                    status = "WARN"
                else:
                    status = "OK"

                for instance in instances:
                    event_sent = True
                    juggler_events.append({
                        'service': SERVICE_NAME % instance,
                        'status': status,
                        'description': "from:downtime-db-notify; Downtime is scheduled at %s (info: %s)" % (
                            downtime, info
                        )
                    })
                    if status != "OK":
                        logging.info(juggler_events[-1])

                break

            if last_ind != 0:
                if last_ind != len(downtimes):
                    new_data = utils.build_node_content(downtimes[last_ind:])
                    logging.info('new content in %s:\n"%s"' % (zk_path, new_data.decode('utf-8')))
                    utils.zkh.set(zk_path, new_data)
                else:
                    logging.info("deleting %s" % zk_path)
                    utils.zkh.delete(zk_path)

        if instances and not event_sent:
            for instance in instances:
                juggler_events.append({
                    'service': SERVICE_NAME % instance,
                    'status': 'OK',
                    'description': 'from:downtime-db-notify; no scheduled downtimes'
                })

    dj.queue_events(juggler_events)
    utils.zkh.stop()


if __name__ == '__main__':
    logging.basicConfig(
        format=u'%(levelname)-8s [%(asctime)s] %(message)s',
        level=logging.INFO,
    )

    try:
        logging.info("START")
        main()
        dj.queue_events([{'service': SERVICE_NAME_WORKING, 'status': 'OK', 'description': ''}])
        logging.info("END")

    except Exception as e:
        logging.exception("unexpected exception")
        dj.queue_events([{
            'service': SERVICE_NAME_WORKING,
            'status': 'CRIT',
            'description': "unexpected exception (%s) %s" % (type(e), e)
        }])

