"""
==================================================
Smart Attendance AI
Embedding Utilities
==================================================
Provides helper functions for working with
face embeddings.
==================================================
"""

from typing import List

import numpy as np


class EmbeddingUtils:

    # ==========================================
    # Convert List -> NumPy
    # ==========================================

    @staticmethod
    def to_numpy(
        embedding: List[float]
    ) -> np.ndarray:
        """
        Convert embedding list into NumPy array.
        """

        return np.asarray(
            embedding,
            dtype=np.float32
        )

    # ==========================================
    # Convert NumPy -> List
    # ==========================================

    @staticmethod
    def to_list(
        embedding: np.ndarray
    ) -> List[float]:
        """
        Convert NumPy array into Python list.
        """

        return embedding.astype(
            np.float32
        ).tolist()

    # ==========================================
    # Validate Embedding Dimension
    # ==========================================

    @staticmethod
    def validate_dimension(
        embedding: List[float],
        dimension: int = 512
    ) -> bool:
        """
        Verify embedding dimension.
        """

        return len(embedding) == dimension

    # ==========================================
    # Normalize Embedding
    # ==========================================

    @staticmethod
    def normalize(
        embedding: List[float]
    ) -> List[float]:
        """
        L2 normalize an embedding.
        """

        vector = EmbeddingUtils.to_numpy(
            embedding
        )

        norm = np.linalg.norm(vector)

        if norm == 0:

            return embedding

        normalized = vector / norm

        return EmbeddingUtils.to_list(
            normalized
        )

    # ==========================================
    # Average Embeddings
    # ==========================================

    @staticmethod
    def average(
        embeddings: List[List[float]]
    ) -> List[float]:
        """
        Compute average embedding.
        """

        if not embeddings:

            return []

        vectors = np.asarray(
            embeddings,
            dtype=np.float32
        )

        average_vector = np.mean(
            vectors,
            axis=0
        )

        norm = np.linalg.norm(
            average_vector
        )

        if norm != 0:

            average_vector /= norm

        return EmbeddingUtils.to_list(
            average_vector
        )

    # ==========================================
    # Stack Embeddings
    # ==========================================

    @staticmethod
    def stack(
        embeddings: List[List[float]]
    ) -> np.ndarray:
        """
        Convert multiple embeddings into
        a NumPy matrix.
        """

        return np.asarray(
            embeddings,
            dtype=np.float32
        )