from __future__ import absolute_import, unicode_literals

import subprocess
from time import sleep

import requests
from celery import shared_task
from celery.utils.log import get_task_logger
from django.conf import settings
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver

from correlation.constants import redis_instance, STARTUP_UPDATE_NAME
from correlation.models import Rule
from correlation.services.rules import to_correlator_data

_log = get_task_logger(__name__)


@shared_task
def initial_task_update(*args, **kwargs):
    _log.info("Init correlator rules")
    done = redis_instance.get(STARTUP_UPDATE_NAME)
    if done == "True":
        _log.info("Already done")
        return

    for iter in range(180):
        if update_correlator_tasks(False):
            redis_instance.set(STARTUP_UPDATE_NAME, "True")
            return
        sleep(1)

    _log.error("Can't set initial correlation rules")


@shared_task
def update_correlator_tasks(clear_store=True):
    # First - remove all rules
    # Next - add new rules
    if clear_store:
        try:
            url = settings.CORRELATOR_URL + '/clear/'
            resp = requests.get(url)
            if resp.status_code != 200:
                _log.error("Store wasn't cleared")
                return False
        except requests.RequestException:
            _log.error("Can't send clear request")
            return False

    rules = Rule.objects.filter(status=True).order_by("pk")
    data = []
    for rule in rules:
        data.append(to_correlator_data(rule))

    if len(data) == 0:
        _log.info("No rules found. Correlator initialization complete")
        return True

    try:
        url = settings.CORRELATOR_URL + '/add_many/'
        headers = {'Content-type': 'application/json',
                   'Accept': 'text/plain',
                   'Content-Encoding': 'utf-8'}
        _log.debug(f"Sending {len(data)} rules to correlator")
        resp = requests.post(url, json=data, headers=headers)
        _log.debug(f"Response code: {resp.status_code}")
        _log.debug(f"Response: {resp.text}")
        return resp.status_code == 200
    except requests.ConnectionError as ex:
        _log.error("Can't send rules to correlator. Reason -> {}".format(ex))
        return False

    _log.info(f"{len(data)} rules sended to correlator")
    return True


@receiver(post_delete, sender=Rule)
@receiver(post_save, sender=Rule)
def sync_rules(sender, **kwargs):
    """ Sync correlation rules after rule delete """
    rule = kwargs['instance']
    if not update_correlator_tasks(True):
        _log.error(f"Can't sync correlator rules after [{rule.name}] delete")
    else:
        _log.info(f"Sync correlator rules after [{rule.name}] delete")


@shared_task
def reboot_correlator_task():
    """HOTFIX Task. rebut correlator and sync rules"""
    _log.info('Rebut correlator')
    subprocess.run(['sudo', 'systemctl', 'restart', 'amccorrelator'],
                   stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    for _ in range(5):
        result = update_correlator_tasks()
        if result:
            break
        sleep(30)  # wait correlator
