import signal
import time
from SKFClient.core.utils.log import log
from SKFClient.core.protocol.mqtt.mqtt_client import MQTTClient
from SKFClient.core.protocol.mqtt.aws_mqtt_client import AWSMQTTClient
from SKFClient.core.protocol.http.http_client import HTTPClient
from SKFClient.core.jobs.app_context import AppContext, JobEnum
from SKFClient.core.jobs.aws_to_lora_job import AwsToLoraJob
from SKFClient.core.jobs.aws_gateway_ping_job import AwsGatewayPingJob
from SKFClient.core.jobs.post_status_job import PostStatusJob
from SKFClient.core.jobs.broker_down_job import LoraToAwsAndBrokerDownJob


class ClientError(RuntimeError):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return str(self.value)


class App:
    def __init__(self, config):
        self.config = config
        self.app_run = False
        log.setLevel(self.config.log_level)

        # create service
        self.local_mqtt_client = MQTTClient(self.config.local_mqtt_config)
        self.aws_mqtt_client = AWSMQTTClient(self.config.aws_mqtt_config)
        self.http_client = HTTPClient(self.config.http_config)

        self.app_context = AppContext(self.config, self.local_mqtt_client, self.aws_mqtt_client, self.http_client)

        # create jobs

        # Publish uplinks
        self.broker_down_job = LoraToAwsAndBrokerDownJob()
        self.app_context.add_job(JobEnum.BROKER_DOWN, self.broker_down_job)

        # Receive downlinks to queue
        self.aws_to_lora_job = AwsToLoraJob()
        self.app_context.add_job(JobEnum.AWS_TO_LORA, self.aws_to_lora_job)

        # Ping every 12 hours to HTTP
        self.aws_gateway_ping_job = AwsGatewayPingJob()
        self.app_context.add_job(JobEnum.AWS_GATEWAY_PING, self.aws_gateway_ping_job)

        # Hourly ping to MQTT
        self.post_status_job = PostStatusJob()
        self.app_context.add_job(JobEnum.POST_STATUS, self.post_status_job)

        # init job
        self.app_context.init_jobs()

    def handler_stop_signals(self, signum, frame):
        self.app_run = False
        log.info("Handle Stop Signals")

    def run(self):
        log.info("Start SKF client")
        self.app_run = True

        signal.signal(signal.SIGINT, self.handler_stop_signals)
        signal.signal(signal.SIGTERM, self.handler_stop_signals)

        self.aws_mqtt_client.run()
        self.local_mqtt_client.run()

        self.app_context.start_jobs()

        while self.app_run:
            time.sleep(5)
            pass


        log.info("Handle Stop MQTT services")
        self.local_mqtt_client.stop()
        self.aws_mqtt_client.stop()

        log.info("Handle Stop jobs")

        self.app_context.stop_jobs()
