class ConvertStreamToFrameService:
    def __init__(self, logger):
        self.broker = Broker(logger)
        self.logger = logger
        self.database = Database(logger)

    def convert_stream_to_frame(self, stream):
        try:
            self.logger.info('converting stream {}'.format(stream))
            result, frames = [], []
            capture = cv2.VideoCapture(stream)
            for index in range(DEFAULT_FPS):
                ret, frame = capture.read()
                encode_param = [
                    int(cv2.IMWRITE_JPEG_QUALITY),
                    int(
                        os.getenv("JPG_IMAGE_QUALITY",
                                  DEFAULT_JPG_IMAGE_QUALITY))
                ]
                ret, buffer = cv2.imencode('.jpg', frame, encode_param)
                encoded_image = base64.b64encode(buffer)
                frames.append(encoded_image.decode('utf-8'))
            capture.release()

            if frames:
                for index in range(
                        int(
                            os.getenv("NUMBER_OF_FRAME_TAKEN",
                                      DEFAULT_NUMBER_OF_FRAME_TAKEN))):
                    selected_index_frame = random.randint(0, DEFAULT_FPS - 1)
                    result.append({
                        'filename':
                        "frame{}.jpg".format(selected_index_frame),
                        'encoded_file':
                        "{}{}".format(DEFAULT_PREFIX_BASE64,
                                      frames[selected_index_frame])
                    })
            return result
        except Exception as error:
            self.logger.error(
                'Cannot Converting Stream to Frame : {}'.format(error))
            return None

    async def upload_encoded(self, payload):
        try:
            self.logger.info('received data from master node : {}'.format(
                payload.filename))
            feedback_url = payload.feedback_url
            ticket_number = await self.upload_image_to_broker(
                feedback_url, upload_type='base64', payload=[payload.dict()])
            return self.show_ticket_number(ticket_number)
        except ValidationError as error:
            return self.process_error(error)
        except Exception as error:
            return self.process_error(error)

    async def upload_raw(self, payload):
        try:
            self.logger.info(
                'received data from master node : {}'.format(payload))
            feedback_url = payload.feedback_url
            ticket_number = await self.upload_image_to_broker(
                feedback_url, upload_type='raw', payload=payload)
            return self.show_ticket_number(ticket_number)
        except Exception as error:
            return self.process_error(error)

    async def upload_url(self, payload):
        try:
            self.logger.info(
                'received data from master node : {}'.format(payload))
            feedback_url = payload.feedback_url
            ticket_number = await self.upload_image_to_broker(
                feedback_url, upload_type='url', payload=payload.dict())
            return self.show_ticket_number(ticket_number)
        except ValidationError as error:
            return self.process_error(error)
        except Exception as error:
            return self.process_error(error)

    def show_ticket_number(self, ticket_number):
        if ticket_number:
            data = {'ticket_number': ticket_number}
            self.logger.info('{} : {}'.format(
                MESSAGE_SUCCESS_SENT_DATA_TO_QUEUE, data))
            return return_message(message=MESSAGE_SUCCESS_SENT_DATA_TO_QUEUE,
                                  data=data)
        else:
            self.logger.error(MESSAGE_INVALID_TICKET_NUMBER)
            return return_message(status=HTTP_STATUS_UNPROCESSABLE_ENTITY,
                                  message=MESSAGE_INVALID_TICKET_NUMBER)

    def process_error(self, error):
        message = "Error when processing received data from master node : {}".format(
            error)
        self.logger.error(message)
        return return_message(status=HTTP_STATUS_UNPROCESSABLE_ENTITY,
                              message=message)

    async def upload_image_to_broker(self, feedback_url, **kwargs):
        upload_type = kwargs.get("upload_type")
        payload = kwargs.get("payload")
        if payload:
            response = json_upload(upload_type=upload_type, payload=payload)
            if response['status'] == HTTP_STATUS_OK:
                token = response['token']
                ticket_number = get_current_timestamp_ms()
                if self.database.add_default_image_result_data(
                        ticket_number, token, feedback_url):
                    sent_payload = {
                        'token': token,
                        'ticket_number': ticket_number
                    }
                    self.logger.info(
                        'sending payload {} to queue'.format(sent_payload))
                    self.broker.produce(
                        topic=os.getenv("KAFKA_IMAGE_PROCESS_TOPIC"),
                        payload=sent_payload)
                    return ticket_number
                else:
                    return None
            else:
                self.logger.error(MESSAGE_UPLOAD_ERROR)
                return None
        else:
            self.logger.warning(MESSAGE_IMAGE_PAYLOAD_EMPTY)
            return None

    async def upload_send_to_broker(self, data, gate_id, stream):
        if data:
            for item in data:
                response_upload = json_upload(upload_type='base64',
                                              payload=[item])
                if response_upload['status'] == HTTP_STATUS_OK:
                    token = response_upload['token']
                    sent_payload = {'gate_id': gate_id, 'token': token}
                    self.logger.info(
                        'sending payload {} to queue.'.format(sent_payload))
                    self.broker.produce(topic=os.getenv("KAFKA_TOPIC"),
                                        payload=sent_payload)
                else:
                    self.logger.error(MESSAGE_UPLOAD_ERROR)
                    return return_message(status=HTTP_STATUS_BAD_REQUEST,
                                          message=MESSAGE_UPLOAD_ERROR)
        else:
            message = '{} [{}]'.format(MESSAGE_CANNOT_READ_STREAM, stream)
            self.logger.warning(message)
            return return_message(status=HTTP_STATUS_BAD_REQUEST,
                                  message=message)

    async def auto_convert(self):
        data = self.database.fetch_data_stream()
        result = []
        if data:
            for state in data:
                url_stream = state.url
                id_gate = state.id_gate
                result.append({'id_gate': id_gate, 'url_stream': url_stream})
                data_payload_queue = self.convert_stream_to_frame(url_stream)
                await self.upload_send_to_broker(data_payload_queue, id_gate,
                                                 url_stream)