import cv2
import time
import base64
import os
import json
from uuid import uuid1
from datetime import datetime
from cachetools import cached, TTLCache
from edge_engine.common.logsetup import logger

from scripts.common.config import MONGO_DB_OBJ, APP_MONGO_COLLECTION

TTL = 5


class InfoCenter:
    def __init__(self, device_id):
        self.camera_key = os.environ.get('app', None)
        self.device_id = device_id
        self.attendance_event_collection = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('eventLogCollection')]
        self.camera_configuration = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('cameraConfigurationCollection')]
        self.camera_mapping_json = self.get_all_cameras()
        self.ttl_check = NotificationFilter()

    def get_all_cameras(self):
        camera_mapping_json = self.camera_configuration.find({'decommissioned': False}, {"_id": 0})
        return {each['cameraId']: each['cameraName'] for each in camera_mapping_json}

    def send_payload(self,
                     frame, can_count, eventtype, box_id,
                     label='Can_Counting_Solution',
                     bg_color="#474520",
                     font_color="#FFFF00",
                     alert_sound=None,
                     message=""):
        frame = cv2.resize(frame, (64, 64))
        payload = {"deviceId": self.device_id,
                   "message": message,
                   "frame": 'data:image/jpeg;base64,' + base64.b64encode(
                       cv2.imencode('.jpg', frame)[1].tostring()).decode("utf-8"),
                   "activity": label,
                   "bg_color": bg_color,
                   "font_color": font_color,
                   "alert_sound": alert_sound,
                   "can_count": can_count,
                   "eventtype": eventtype, "box_id": box_id}

        self.insert_attendance_event_to_mongo(payload)

    def get_box_count(self):
        try:
            return self.attendance_event_collection.find(
                {
                    'app': 'can'
                }
            ).count()

        except Exception as e:
            logger.info(e)
            logger.error(traceback.format_exc())

    def insert_attendance_event_to_mongo(self, data):
        try:
            input_data = {
                "eventId": str(uuid1()).split('-')[0],
                "cameraId": data['deviceId'],
                "cameraName": self.camera_mapping_json.get(data['deviceId'], "iLens Camera"),
                "timestamp": datetime.now(),
                "frame": data['frame'],
                "eventtype": data['eventtype'],
                "bg_color": data["bg_color"],
                "font_color": data["font_color"],
                "intrusion_message": data["message"],
                "alert_sound": data["alert_sound"],
                "can_count": data["can_count"],
                "box_id": data["box_id"],
                "app": 'can'
            }

            logger.debug("Pushing to Mongo..")
            self.attendance_event_collection.insert(input_data)
        except Exception as e:
            logger.error(f"Exception occurred: {e}", exc_info=True)


class NotificationFilter(object):

    def __init__(self, ttl_value=3):
        """init function
        """
        global TTL
        TTL = ttl_value
        self.TTL = ttl_value
        self.face_id_cache = {}

    def _update_cache(self, name):
        """updates the cache with a name

        Args:
            name (str): Name of the person
        """
        self.face_id_cache[name] = time.time()

    def check_rpt(self, name):
        """Returns a boolean if the notification center has to be notified
        or not

        Args:
            name (str): name of person identified

        Returns:
            notify (bool): True if notification to be sent False if the
            notification is not to be sent
        """
        self._clean_up_cache()
        if name is None:
            notify = False
        else:
            is_present = self.face_id_cache.get(name, -1)
            if is_present == -1:
                notify = True
                self._update_cache(name)
            else:
                notify = False
        return notify

    @cached(cache=TTLCache(maxsize=1024, ttl=TTL))
    def _clean_up_cache(self):
        """Cleans up the cached name at regular interval
        """
        key_to_delete = [
            key
            for key, value in self.face_id_cache.items()
            if time.time() - value >= self.TTL
        ]

        for key in key_to_delete:
            del self.face_id_cache[key]
