from edge_engine.common.logsetup import logger
from edge_engine.common.config import EDGE_CONFIG
from edge_engine.streamio.datastream import MQTT
from edge_engine.streamio.datastream import VideoOutputStream
from edge_engine.streamio.datastream import FrameOutputStream
from edge_engine.streamio.datastream import FFMPEGOutputStream, OPENCVOutputStream
from edge_engine.streamio.datastream import MongoDataStreamOut
from edge_engine.streamio.videostream import ThreadedVideoStream
from edge_engine.streamio.videostream import FileVideoStream
from edge_engine.streamio.datastream import DummyPublisher
from edge_engine.streamio.frameProcessor import FrameProcessor
from edge_engine.common.minio_server import MinioClient
import json
from threading import Thread
import os


class Pubs():

    def __init__(self):
        self.mqtt_pub = DummyPublisher(name="MQTT")
        self.frame_write = DummyPublisher(name="FRAME")
        self.video_write = DummyPublisher(name="VIDEO")
        self.mongo_write = DummyPublisher(name="MONGO")
        self.rtp_write = DummyPublisher(name="RTP")
        self.build_pubs()
        if 'minioConfig' in EDGE_CONFIG.keys() and \
                isinstance(EDGE_CONFIG["minioConfig"], dict):
            self.minio_thread = self.start_minio(EDGE_CONFIG["minioConfig"])

    @staticmethod
    def start_minio(minio_conf):
        obj = MinioClient(minio_conf['secretKey'], minio_conf['accessKey'],
                          minio_conf['bucketName'], minio_conf['localDataPath'],
                          minio_conf['ip'])
        t = Thread(target=obj.upload)
        t.start()
        return t

    def build_pubs(self):
        logger.info("building publishers ")
        state = os.environ.get('state', 'prod')
        for conf in EDGE_CONFIG["pubConfigs"]:
            if conf["type"].upper() == "MQTT":
                self.mqtt_pub = MQTT(broker=conf["broker"], topic=conf["topic"], port=conf["port"]
                                     , publish_hook=json.dumps)

            elif conf["type"].upper() == "FRAMEWRITE":
                self.frame_write = FrameOutputStream(
                    basepath=conf["basepath"],
                    iformat=conf["iformat"],
                    filenameFormat=conf["filenameFormat"],
                    publish_hook=None)

            elif conf["type"].upper() == "VIDEOWRITE":
                self.video_write = VideoOutputStream(basepath=conf["basepath"],
                                                     dims=conf["dims"],
                                                     filenameFormat=conf["filenameFormat"],
                                                     fps=conf["fps"], publish_hook=None)

            elif conf["type"].upper() == "MONGO":
                self.mongo_write = MongoDataStreamOut(host=conf["host"],
                                                      port=conf["port"],
                                                      dbname=conf["dbname"],
                                                      collection=conf["collection"],
                                                      keys=conf["keys"],
                                                      authsource=conf["authSource"],
                                                      username=conf["username"],
                                                      password=conf["password"],
                                                      publish_hook=None)
            elif conf["type"].upper() == "RTP":

                self.rtp_write = FFMPEGOutputStream(conf["ffmpegCmd"], conf["RTPEndpoint"], publish_hook=None)

            elif conf["type"].upper() == "OPENCV":
                logger.info('Dev Testing, Video output will be loaded on new window')
                self.rtp_write = OPENCVOutputStream()
            else:
                logger.error("Unsupported publisher {}".format(conf["type"]))


class ExecutePipeline:
    def __init__(self, model):
        self.model = model

    def run_model(self):
        if EDGE_CONFIG["inputConf"]["sourceType"].lower() in ["rtsp", "usbcam"]:
            logger.info("Selected input stream as Direct cv input")
            self.threadedVideoStream = ThreadedVideoStream(stream_config=EDGE_CONFIG["inputConf"])
            self.threadedVideoStream.start()
            self.frameProcessor = FrameProcessor(stream=self.threadedVideoStream,
                                                 model=self.model)
        elif EDGE_CONFIG["inputConf"]["sourceType"].lower() == "videofile":
            self.fileVideoStream = FileVideoStream(stream_config=EDGE_CONFIG["inputConf"])
            self.fileVideoStream.start()
            self.frameProcessor = FrameProcessor(stream=self.fileVideoStream, model=self.model)
        else:
            raise ValueError("unsupported source  {}".format(EDGE_CONFIG["inputConf"]["sourceType"]))

        self.start_model()

    def start_model(self):
        self.frameProcessor.run_model()
