import abc

import numpy as np
from deepface import DeepFace


class VisualEmotionRecognizer(abc.ABC):
    @abc.abstractmethod
    def load_model(self):
        """Load the visual emotion recognition model into memory."""
        pass

    @abc.abstractmethod
    def sorted_dominant_emotions(self, image) -> list[str]:
        """
        Recognize dominant emotions from faces in the given image.
        Emotions can be one of ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'].
        To minimize false positives, consider filtering faces with low confidence.

        :param image: The input image for emotion recognition.
        :return: List of dominant emotion detected for each face in the image, 
        sorted per face.
        """
        pass

class DeepFaceEmotionRecognizer(VisualEmotionRecognizer):
    """
    DeepFace-based implementation of VisualEmotionRecognizer.
    DeepFape has proven to be quite a pessimistic model, so expect sad, fear and neutral 
    emotions to be over-represented.
    """
    def __init__(self):
        self.load_model()
    
    def load_model(self):
        dummy_img = np.zeros((224, 224, 3), dtype=np.uint8)
        # analyze does not take a model as an argument, calling it once on a dummy image to load 
        # the model
        DeepFace.analyze(dummy_img, actions=['emotion'], enforce_detection=False)

    def sorted_dominant_emotions(self, image) -> list[str]:
        analysis = DeepFace.analyze(image, 
                                    actions=['emotion'], 
                                    enforce_detection=False
                                    )
        
        # Sort faces by x coordinate to maintain left-to-right order
        analysis.sort(key=lambda face: face['region']['x'])

        analysis = [face for face in analysis if face['face_confidence'] >= 0.90]
        
        dominant_emotions = [face['dominant_emotion'] for face in analysis]
        return dominant_emotions
