# -*- coding: utf-8 -*-
###########################################################################
# Copyright (c), The AiiDA team. All rights reserved.                     #
# This file is part of the AiiDA code.                                    #
#                                                                         #
# The code is hosted on GitHub at https://github.com/aiidateam/aiida_core #
# For further information on the license, see the LICENSE.txt file        #
# For further information please visit http://www.aiida.net               #
###########################################################################
import logging
import signal
from functools import partial

from aiida.common.log import configure_logging
from aiida.daemon.client import DaemonClient
from aiida.work.rmq import get_rmq_config
from aiida.work import DaemonRunner, set_runner


logger = logging.getLogger(__name__)

DAEMON_LEGACY_WORKFLOW_INTERVAL = 30


def start_daemon():
    """
    Start a daemon runner for the currently configured profile
    """
    daemon_client = DaemonClient()
    configure_logging(daemon=True, daemon_log_file=daemon_client.daemon_log_file)

    runner = DaemonRunner(rmq_config=get_rmq_config(), rmq_submit=False)

    def shutdown_daemon(num, frame):
        logger.info('Received signal to shut down the daemon runner')
        runner.close()

    signal.signal(signal.SIGINT, shutdown_daemon)
    signal.signal(signal.SIGTERM, shutdown_daemon)

    logger.info('Starting a daemon runner')

    set_runner(runner)
    tick_legacy_workflows(runner)

    try:
        runner.start()
    except SystemError as exception:
        logger.info('Received a SystemError: {}'.format(exception))
        runner.close()

    logger.info('Daemon runner stopped')


def tick_legacy_workflows(runner, interval=DAEMON_LEGACY_WORKFLOW_INTERVAL):
    """
    Function that will call the legacy workflow stepper and ask the runner to call the
    same function back after a certain interval, essentially polling the worklow stepper

    :param runner: the DaemonRunner instance to perform the callback
    :param interval: the number of seconds to wait between callbacks
    """
    logger.debug('Ticking the legacy workflows')
    legacy_workflow_stepper()
    runner.loop.call_later(interval, partial(tick_legacy_workflows, runner))


def legacy_workflow_stepper():
    """
    Function to tick the legacy workflows
    """
    from datetime import timedelta
    from aiida.daemon.timestamps import set_timestamp_workflow_stepper, get_timestamp_workflow_stepper
    from aiida.daemon.workflowmanager import execute_steps

    logger.debug('Checking for workflows to manage')
    # RUDIMENTARY way to check if this task is already running (to avoid acting
    # again and again on the same workflow steps)
    try:
        stepper_is_running = (get_timestamp_workflow_stepper(when='stop')
                              - get_timestamp_workflow_stepper(when='start')) <= timedelta(0)
    except TypeError:
        # When some timestamps are None (undefined)
        stepper_is_running = (get_timestamp_workflow_stepper(when='stop')
                              is None and get_timestamp_workflow_stepper(when='start') is not None)

    if not stepper_is_running:
        # The previous wf manager stopped already -> we can run a new one
        set_timestamp_workflow_stepper(when='start')
        logger.debug('Running execute_steps')
        execute_steps()
        set_timestamp_workflow_stepper(when='stop')
    else:
        logger.debug('Execute_steps already running')
