import os
import json

from ansible import constants as C
from ansible.plugins.callback import CallbackBase
from django.conf import settings

try:
    from __main__ import display as global_display
except ImportError:
    from ansible.utils.display import Display
    global_display = Display()


class AdHocCallback(CallbackBase):
    def __init__(self, runner, host_list):
        super(AdHocCallback, self).__init__()
        self.runner = runner
        self.host_list = host_list

    @staticmethod
    def __extract_result(result):
        return result._host.get_name(), result._result

    def __save_result(self, host, status, message, result):
        runner_task = self.runner.task_set.latest('id')
        query_set = runner_task.result_set.filter(host=host)
        host = query_set[0]
        host.status = status
        host.message = message
        host.response = result
        host.save()

    def v2_playbook_on_play_start(self, play):
        self.runner.status = 'running'
        self.runner.save()

    def v2_playbook_on_task_start(self, task, is_conditional):
        runner_task = self.runner.task_set.create(name=task.get_name().strip())
        for host in self.host_list:
            runner_task.result_set.create(host=host, status='started', response='{}')

    def v2_playbook_on_no_hosts_matched(self):
        self.runner.message = 'No hosts matched'
        self.runner.save()

    def v2_playbook_on_stats(self, stats):
        print 'play stats: ' + str(stats)

    def v2_runner_on_failed(self, result, ignore_errors=False):
        host, response = self.__extract_result(result)
        module = str(response['invocation']['module_name'])
        message = module + ' failed'
        if 'exception' in response:
            message = 'Exception raised'
            response = [response]
        elif module == 'shell' or module == 'script':
            message = response['stdout'] + response['stderr']
        self.__save_result(host, 'failed', message, response)

    def v2_runner_on_ok(self, result):
        host, response = self.__extract_result(result)
        module = str(response['invocation']['module_name'])
        message = module + ' successful'
        status = 'ok'
        if module == 'setup':
            facts = {'ansible_facts': response['ansible_facts']}
            filename = (os.path.join(settings.FACTS_DIR, host))
            with open(filename, "w") as f:
                f.write(json.dumps(facts, indent=4))
                response['ansible_facts'] = 'saved to file'
                message = 'Facts saved to ' + filename
        elif module == 'command' or module == 'script':
            message = response['stdout'] + response['stderr']
        elif response['changed']:
            status = 'changed'
        self.__save_result(host, status, message, response)

    def v2_runner_on_skipped(self, result):
        host, response = self.__extract_result(result)
        self.__save_result(host, 'skipped', host + ' skipped', {})

    def v2_runner_on_unreachable(self, result):
        host, response = self.__extract_result(result)
        if 'msg' in response:
            message = response['msg']
        else:
            message = 'Host unreachable'
            response = [response]
        self.__save_result(host, 'unreachable', message, response)


class PlaybookCallback(CallbackBase):

    def __init__(self, runner, host_list):
        super(PlaybookCallback, self).__init__()
        self.runner = runner
        self.host_list = host_list

    @staticmethod
    def _extract_result(result):
        return result._host.get_name(), result._result

    def _save_result(self, host, status, message, result):
        runner_task = self.runner.task_set.latest('id')
        query_set = runner_task.result_set.filter(host=host)
        host = query_set[0]
        host.status = status
        host.message = message
        host.response = result
        host.save()

    def v2_playbook_on_play_start(self, play):
        self.runner.status = 'running'
        self.runner.save()

    def v2_playbook_on_task_start(self, task, is_conditional):
        runner_task = self.runner.task_set.create(name=task.get_name().strip(), module=task.action)
        for host in self.host_list:
            runner_task.result_set.create(host=host, status='started', response='{}')

    def v2_playbook_on_no_hosts_matched(self):
        self.runner.message = 'No hosts matched'
        self.runner.save()

    def v2_playbook_on_stats(self, stats):