"""InsightFace buffalo_l wrapper for face detection and embedding extraction."""

import logging

import numpy as np
from insightface.app import FaceAnalysis

logger = logging.getLogger(__name__)


class FaceAnalyzer:
    """Wraps insightface FaceAnalysis (buffalo_l) for detection + 512-d embedding."""

    def __init__(self, model_name: str = "buffalo_l", ctx_id: int = -1, det_thresh: float = 0.3):
        self._app = FaceAnalysis(name=model_name, providers=["CPUExecutionProvider"])
        self._app.prepare(ctx_id=ctx_id, det_size=(640, 640))
        # Lower detection threshold for varied lighting/angle (smart mirror use case)
        if hasattr(self._app, "det_model") and hasattr(self._app.det_model, "det_thresh"):
            self._app.det_model.det_thresh = det_thresh
        logger.info("FaceAnalyzer initialized (model=%s, det_thresh=%s)", model_name, det_thresh)

    def get_embeddings(self, image: np.ndarray) -> list[np.ndarray]:
        """Detect faces and return list of 512-d embedding vectors.

        Args:
            image: BGR numpy array (OpenCV format).

        Returns:
            List of normalized embedding vectors (one per detected face).
        """
        faces = self._app.get(image)
        if not faces:
            return []
        embeddings = []
        for face in faces:
            emb = face.normed_embedding
            embeddings.append(emb.astype(np.float32))
        return embeddings

    def get_largest_face_embedding(self, image: np.ndarray) -> np.ndarray | None:
        """Return embedding of the largest detected face (by bbox area).

        Args:
            image: BGR numpy array (OpenCV format).

        Returns:
            512-d embedding vector, or None if no face detected.
        """
        faces = self._app.get(image)
        if not faces:
            return None
        largest = max(faces, key=lambda f: (f.bbox[2] - f.bbox[0]) * (f.bbox[3] - f.bbox[1]))
        return largest.normed_embedding.astype(np.float32)
