import json
import logging

from bustoken import (
    TK_MAINTENANCE_TERMINATE_REQUEST,
    TK_MAINTENANCE_RESTART_REQUEST,
    TK_MAINTENANCE_RECREATE_FILES_XML,
    TK_MAINTENANCE_RECREATE_FILE_NUMBER,
    TK_MAINTENANCE_CLEAN_AUDIT_LOG,
    TK_MAINTENANCE_DATABASE_CLEANUP_STATUS,
)
from events import (
    CleanDatabasesProcessor,
    MaintenanceProcessor
)
from messagehandler import EventHandler
from msgbus import (
    MBEasyContext,
    MBMessage,
    TK_SYS_ACK,
    TK_SYS_NAK,
)
from systools import sys_log_exception


logger = logging.getLogger("Maintenance")


class MaintenanceEventHandler(EventHandler):
    def __init__(
        self,
        mb_context,                 # type: MBEasyContext
        maintenance_processor,      # type: MaintenanceProcessor
        clean_databases_processor   # type: CleanDatabasesProcessor
    ):
        # type: (...) -> None

        super(MaintenanceEventHandler, self).__init__(mb_context)
        self.mb_context = mb_context
        self.maintenance_processor = maintenance_processor
        self.clean_databases_processor = clean_databases_processor

    def subscribe_events(self, subject):
        return

    def terminate_event(self):
        return

    @staticmethod
    def get_handled_tokens():
        return [
            TK_MAINTENANCE_TERMINATE_REQUEST,
            TK_MAINTENANCE_RESTART_REQUEST,
            TK_MAINTENANCE_RECREATE_FILES_XML,
            TK_MAINTENANCE_RECREATE_FILE_NUMBER,
            TK_MAINTENANCE_DATABASE_CLEANUP_STATUS
        ]

    def handle_event(
        self,
        subject,  # type: unicode
        evt_type,  # type: unicode
        data,  # type: str
        msg,  # type: MBMessage
    ):
        # type: (...) -> None

        logger.info("Event received: [{}]".format(subject))

        try:
            logger.info("Not inside maintenance window. Exiting...")
            event_data = json.loads(data)
            return
        except Exception:  # noqa
            logger.exception("error parsing event data as json")
            event_data = {}
        ignore_maintenance_window = event_data.get("ignoreMaintenanceWindow", False)
        if not ignore_maintenance_window:
            if not self.maintenance_processor.is_inside_maintenance_window():
                logger.info("Not inside maintenance window. Exiting...")
                return

        if subject == "CleanDatabaseBackups":
            self.clean_databases_processor.clean_database_backups()
        elif subject == "CleanDatabases":
            vacuum = event_data.get("vacuum", False)
            self.clean_databases_processor.clean_databases(vacuum)
        elif subject == "VacuumDatabases":
            self.clean_databases_processor.vacuum_databases()

    def handle_message(self, msg):
        try:
            if msg.token == TK_MAINTENANCE_TERMINATE_REQUEST:
                response = self.maintenance_processor.handle_terminate_request(msg)
            elif msg.token == TK_MAINTENANCE_RESTART_REQUEST:
                response = self.maintenance_processor.handle_restart_request(msg)
            elif msg.token == TK_MAINTENANCE_CLEAN_AUDIT_LOG:
                response = self.maintenance_processor.clean_audit_log()
            elif msg.token == TK_MAINTENANCE_DATABASE_CLEANUP_STATUS:
                response = self.maintenance_processor.handle_database_cleanup_status()
            else:
                response = (False, "")

            msg.token = TK_SYS_ACK if response[0] else TK_SYS_NAK
            self.mb_context.MB_ReplyMessage(msg, data=response[1])
        except Exception as ex:
            sys_log_exception("Unexpected exception handling event: {}".format(msg.token))
            msg.token = TK_SYS_NAK
            self.mb_context.MB_ReplyMessage(msg, data=str(ex))
