
from .dm import SIGNALS

from .golovan import golovan_patch
from .golovan import golovan_get

from .golovan import alert_ctype_from_name
from .golovan import alert_key_from_name

from .juggler import alert_key_from_juggler_tags
from .juggler import alert_ctype_from_juggler_tags
from .juggler import set_flap  # noqa
from .juggler import set_notify  # noqa
from .juggler import extract_golovan_names
from .juggler import extract_flaps
from .juggler import extract_phone_times
from .juggler import extract_phone_users
from .juggler import _juggler_rpc

from .dm import patch_conf
from .dm import patch_conf_common
from .dm import get_alerts_conf  # noqa
from .dm import alert_keys_from_conf
from .dm import flaps_from_conf
from .dm import ring_times_from_conf
from .dm import logins_from_conf
from .dm import is_users_from_conf
from .dm import should_have_juggler
from .dm import should_have_golem


from saas_deploy.cluster import alerts_commands as dm_alerts

import json


def is_alert_for_key(gol_name, sig_key):
    return sig_key in gol_name.split('.')


def compare_limits(d_present, d_need):
    lim_present = limits_yasm2conf(d_present)
    if 'value_modify' in d_present:
        lim_present['avgsec'] = d_present['value_modify'].get('window', 0)
    lim_need = dict([(k, v) for k, v in d_need.get('limits').items() if k not in ('should_sla', 'from_sla')])
    return lim_present == lim_need


def alert_dc_from_name(alert_id):
    LOCS = ['man', 'vla', 'sas', 'msk']
    loc = [l for l in LOCS if l in alert_id.split('.')]
    return loc[0] if loc else 'all'


def is_default_service(service):
    return service in ('default', 'defaults', 'common')


def phone_times_to_str(times):
    if not times:
        return 'always'
    return str(times.get('time_start')) + '-' + str(times.get('time_end'))


def limits_conf2yasm(conf_limits):
    warn = conf_limits['warn']
    crit = conf_limits['crit']
    if warn <= crit:
        return {'warn': [warn, crit],
                'crit': [crit, None]}
    else:
        return {'warn': [crit, warn],
                'crit': [None, crit]}


def limits_yasm2conf(gol_limits):
    max_warn = gol_limits['warn'][1]
    max_crit = max([c for c in gol_limits['crit'] if c is not None])
    if max_warn > max_crit:
        return {'warn': gol_limits['warn'][1],
                'crit': gol_limits['crit'][1]}
    else:
        return {'warn': gol_limits['warn'][0],
                'crit': gol_limits['crit'][0]}


def get_alerts(host='', service='', ctype='', sigkey='', fill_resps=True):
    data_dict = {'include_children': True,
                 'include_notifications': True}
    if host:
        data_dict['host_name'] = host
    gol_alerts = []
    dd_tags = ['saas_autogen', ]
    if service or ctype:
        if service:
            dd_tags.append('saas_service_' + service)
        if ctype:
            dd_tags.append('saas_ctype_' + ctype)
        if sigkey:
            dd_tags.append('saas_skey_' + sigkey)
        name_pattern = 'saas\\.gen\\.'
        if ctype:
            name_pattern += ctype + '\\.'
        else:
            name_pattern += '.*\\.'
        if service:
            name_pattern += service + '\\.'
        gol_alerts_1 = golovan_get({'name_pattern': name_pattern})
        if gol_alerts_1['success']:
            gol_alerts.extend(json.loads(gol_alerts_1['answer'])['response']['result'])
        else:
            return gol_alerts_1
        if sigkey:
            gol_alerts = [ga for ga in gol_alerts if is_alert_for_key(ga['name'], sigkey)]

    data_dict['tag_name'] = ' . '.join(dd_tags)
    res = _juggler_rpc('checks/checks', data_dict)
    if not res['success']:
        return res
    gol_jug_names = extract_golovan_names(res['answer'])
    for al in gol_alerts:
        al['has_juggler'] = al['name'] in gol_jug_names
    return {'juggler': res['answer'], 'golovan': gol_alerts, 'success': True}


def set_alert(service, ctype, is_meta, do_juggler=False):
    ans_raw, err = dm_alerts.actualize(service, ctype)
    if err:
        try:
            err = json.loads(err['answer'])
        except:
            pass
        return {'success': False, 'answer': err}
    ans = json.loads(ans_raw)
    ans['success'] = True
    return ans


def change_alert_by_id(alert_id, fields, service, subject='limits'):
    alert_ids = [alert_id, ]
    res = golovan_patch(alert_ids, fields)
    return res


def change_alert(alert_key, fields, service, subject='limits', login='unknown'):
    if alert_key == 'common':
        return patch_conf_common(service, fields, subject, login=login)
    if alert_key not in SIGNALS():
        return {'success': False, 'error': 'no such alert key found'}
    a_key = alert_key
    patch_res = patch_conf(service, a_key, {subject: fields}, login=login)
    if not patch_res['success']:
        return patch_res
    if is_default_service(service):
        actz_res, actz_err = dm_alerts.actualize_total()
        return {'id': actz_res, 'error': actz_err, 'success': not actz_err}
    al_res = get_alerts('', service=service, sigkey=a_key)
    if not al_res['success']:
        return al_res
    if subject == 'limits':
        al_list = al_res['golovan']
        alert_ids = [al['name'] for al in al_list if '.stable' in al['name']]
        fields_yasm = limits_conf2yasm(fields)
        if fields.get('avgsec'):
            fields_yasm['value_modify'] = {'type': 'aver', 'window': fields.get('avgsec') or 5}
        res = golovan_patch(alert_ids, fields_yasm)
        return res
    elif subject == 'flaps':
        res = {'success': True}
        #  for g_host, jugs in al_res['juggler'].items():
        #      for juggler_id, jdata in jugs.items():
        #          res1 = set_flap(g_host=g_host, juggler_id=juggler_id, flaps=fields)
        #          if not res1['success']:
        #              res.update(res1)
        return res
    elif subject == 'phone_times':
        res = {'success': True}
    #    for g_host, jugs in al_res['juggler'].items():
    #        for juggler_id, jdata in jugs.items():
    #            res1 = set_notify(g_host=g_host, juggler_id=juggler_id,
    #                              template_name='golem', options=fields)
    #            if not res1['success']:
    #                res.update(res1)
        return res
    elif subject == 'disable_notify':
        return patch_res
    elif subject == 'is_users':
        return patch_res
    else:
        return {'error': 'no such subject "' + subject + '" or no is_key', 'success': False}


def reformat_alerts_data(data, golovans, conf, ctypes, is_meta):
    is_default = 'all' in ctypes
    keys_conf = alert_keys_from_conf(conf, list_all=is_default, is_meta=is_meta)
    keys_conf_on = alert_keys_from_conf(conf) if is_default else []
    resd = dict([(ctype, {'mustbe': True,
                          'sigkeys': dict([(skey, {'mustbe': True,
                                                   'signals': [],
                                                   'golovans': []}) for skey in keys_conf]),
                          'ctype': ctype})
                 for ctype in ctypes])
    for skey in keys_conf:
        for ctype in ctypes:
            resd[ctype]['sigkeys'][skey]['limits'] = {
                'conf': conf['data'].get(skey, {}).get('limits', {})
            }
            resd[ctype]['sigkeys'][skey]['flaps'] = {
                'conf': flaps_from_conf(conf, skey) or {}
            }
            resd[ctype]['sigkeys'][skey]['calls_time'] = {
                'conf': ring_times_from_conf(conf, skey) or {}
            }
            resd[ctype]['sigkeys'][skey]['users'] = {
                'conf': logins_from_conf(conf, False, skey) or {},
                'group': 'user' if is_users_from_conf(conf, skey) else 'dev'
            }
            resd[ctype]['sigkeys'][skey]['should_have_juggler'] =\
                should_have_juggler(conf, skey)
            resd[ctype]['sigkeys'][skey]['should_have_golem'] =\
                should_have_golem(conf, skey)
            if is_default:
                resd[ctype]['sigkeys'][skey]['is_on'] = skey in keys_conf_on

    for g in golovans:
        ctype = alert_ctype_from_name(g['name'])
        ctres = resd.get(ctype)
        if not ctres:
            resd[ctype] = {'mustbe': False, 'sigkeys': {}, 'ctype': ctype}
            ctres = resd[ctype]
        skey = alert_key_from_name(g['name'])
        skres = ctres['sigkeys'].get(skey)
        if not skres:
            ctres['sigkeys'][skey] = {'signals': [], 'mustbe': False,
                                      'limits': {}, 'flaps': {},
                                      'calls_time': {}, 'users': {},
                                      'should_have_juggler': 0,
                                      'should_have_golem': 0,
                                      'golovans': []}
            skres = ctres['sigkeys'][skey]
        skres['golovans'].append(g)
        skres['limits']['golovan'] = skres['limits'].get('golovan', [])
        skres['limits']['golovan'].append({'avgsec': (g.get('value_modify') or {}).get('window', 0),
                                           'loc': alert_dc_from_name(g['name'])})
        skres['limits']['golovan'][-1].update(limits_yasm2conf(g))

    for golem_host, gh_data in data.items():
        for juggler_id, jid_data in gh_data.items():
            ctype = alert_ctype_from_juggler_tags(jid_data['tags'])
            ctres = resd.get(ctype)
            if not ctres:
                resd[ctype] = {'mustbe': False, 'sigkeys': {}, 'ctype': ctype}
                ctres = resd[ctype]
            skey = alert_key_from_juggler_tags(jid_data['tags'])
            skres = ctres['sigkeys'].get(skey)
            if not skres:
                ctres['sigkeys'][skey] = {'signals': [], 'mustbe': False,
                                          'limits': {}, 'flaps': {},
                                          'calls_time': {}, 'users': {},
                                          'should_have_juggler': 0,
                                          'should_have_golem': 0,
                                          'golovans': []}
                skres = ctres['sigkeys'][skey]
            skres['flaps']['juggler'] = skres['flaps'].get('juggler', [])
            skres['flaps']['juggler'].append(extract_flaps(jid_data))

            skres['users']['golem'] = extract_phone_users(jid_data)
            skres['calls_time']['juggler'] = skres['calls_time'].get('juggler', [])
            skres['calls_time']['juggler'].append({})
            skres['calls_time']['juggler'][-1].update(extract_phone_times(jid_data))

            jid_data['golem_host'] = golem_host
            skres['signals'].append({'juggler': {'juggler_id': juggler_id},
                                     'golovan': []})
            skres['signals'][-1]['juggler']['notifications'] = jid_data.pop('notifications')
            used_alerts = jid_data.pop('children')
            used_al_names = [ch['service'] for ch in used_alerts]
            skres['signals'][-1]['juggler']['golovan_signals'] = used_alerts
            skres['signals'][-1]['juggler']['other'] = jid_data
            skres['signals'][-1]['golovan'] = [al for al in golovans
                                               if al['name'] in used_al_names]

    res = [dat for dat in resd.values()]
    for ctd in res:
        for skey, skdat in ctd['sigkeys'].items():
            skdat['has_diff'] = False
            if not skdat['mustbe'] or not ctd['mustbe']:
                skdat['limits']['ro'] = True
                skdat['has_diff'] = True
                continue
            lim_joined = skdat['limits'].get('conf')
            lim_sames = True
            for lim in skdat['limits'].get('golovan', []):
                if lim_joined.get('warn') != lim.get('warn')\
                        or lim_joined.get('crit') != lim.get('crit')\
                        or lim_joined.get('avgsec', 0) != lim.get('avgsec', 0):
                    lim_sames = False
                    skdat['has_diff'] = True
            skdat['limits']['same_limits'] = lim_sames

            has_jugglers = []
            for gc in skdat['golovans']:
                has_jugglers.append(gc.get('has_juggler'))
            hj_statuses = list(set(has_jugglers))
            skdat['has_juggler_inconsist'] = len(hj_statuses) > 1
            skdat['has_juggler'] = True in hj_statuses
            if skdat['has_juggler_inconsist'] or not hj_statuses:
                skdat['has_juggler_list'] = ','.join([str(h) for h in has_jugglers])
            else:
                skdat['has_juggler_list'] = hj_statuses[0]
            if skdat['has_juggler'] != skdat['should_have_juggler']:
                skdat['has_juggler_inconsist'] = True
                skdat['has_diff'] = True

            flaps_joined = skdat['flaps'].get('conf', {})
            same_flaps = True
            for fl in skdat['flaps'].get('juggler', []):
                if flaps_joined.get('critical_time', 0) != fl['critical_time'] \
                        or flaps_joined.get('stable_time', 0) != fl['stable_time'] \
                        or flaps_joined.get('boost_time', 0) != fl['boost_time']:
                    same_flaps = False
                    skdat['has_diff'] = True
            skdat['flaps']['same_flaps'] = same_flaps

            skdat['users']['same'] = not skdat['has_juggler'] or not skdat['should_have_juggler']\
                or not skdat['should_have_golem']\
                or (skdat['users'].get('conf', []) == skdat['users'].get('golem', []))
            skdat['calls_time']['conf'] = skdat['calls_time'].get('conf', {})
            skdat['calls_time']['conf_str'] = phone_times_to_str(skdat['calls_time']['conf'])
            jtms = list(set([phone_times_to_str(jt) for jt in skdat['calls_time'].get('juggler', [])]))
            skdat['calls_time']['same'] = (len(jtms) == 1 and jtms[0] == skdat['calls_time']['conf_str']) \
                or not jtms or not skdat['should_have_golem']
            skdat['calls_time']['juggler_str'] = ';'.join(jtms)
            skdat['notif'] = {}
            if not skdat['users']['same'] or not skdat['calls_time']['same']:
                skdat['has_diff'] = True

    return {'juggler': res, 'golovan': golovans}
