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
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.frameProcessor import FrameProcessor, FrameProcessorv2
from edge_engine.common.minio_server import MinioClient
import json
from threading import Thread
import time
import os

from edge_engine.streamio.videostream.filepathvideostream import FilePathVideoStream

class Pubs():

    def __init__(self):
        self.mqtt_pub = None
        self.frame_write = None
        self.video_write = None
        self.mongo_write = None
        self.rtp_write = None
        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 ")
        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)
            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)

        
        elif EDGE_CONFIG["inputConf"]["sourceType"].lower() == "videopath":
            processed_videos = []
            videopath = EDGE_CONFIG["inputConf"].get('uri',"")
            while True:
                time1= time.time()

                video_files = os.listdir(videopath)                
                if not video_files:
                    time.sleep(0.01)
                    continue
                video_files.sort()
                for video in video_files:
                    if video in processed_videos:
                        continue
                    if not video.endswith(".mp4"):
                        processed_videos.append(video)
                        continue
                                      
                    processed_videos.append(video)
                    
                    EDGE_CONFIG["inputConf"]['uri'] = os.path.join(videopath, video)
                    self.fileVideoStream = FilePathVideoStream(EDGE_CONFIG["inputConf"]['uri'])
                    self.fileVideoStream.start()
                    self.frameProcessor = FrameProcessorv2(stream=self.fileVideoStream, model=self.model)
                    self.start_model()
                    logger.info("---------------")
                    logger.info(time.time()-time1)
                    # logger.info(int(time.time())-time2)
                    # logger.info(int(time.time())-time3)
                    logger.info("---------------")


        else:
            raise ValueError("unsupported source  {}".format(EDGE_CONFIG["inputConf"]["sourceType"]))

        self.start_model()

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