"""Keep a user's Rekognition face entry in sync with their profile photo.

The avatar is the enrollment source: setting a profile photo indexes that face
under ExternalImageId = str(user.id), which is what AttendanceViewSet.face_check
compares against. Avatars are not always enrollment-grade (group shot, no face,
illustration), so failures here are non-fatal — the avatar still saves, and the
user falls back to the manual enroll screen.
"""

import logging

from botocore.exceptions import ClientError

from .rekognition import delete_faces_for, ensure_collection, index_face

logger = logging.getLogger(__name__)


def sync_face_from_avatar(user) -> bool:
    """Index user.avatar as their face. Returns True if a face was indexed.

    Safe to call from a background thread: never raises.
    """
    external_id = str(user.id)

    if not user.avatar:
        try:
            ensure_collection()
            delete_faces_for(external_id)
        except (ClientError, OSError):
            logger.exception("face de-enrollment failed for user %s", external_id)
        return False

    try:
        with user.avatar.open("rb") as fh:
            image_bytes = fh.read()
    except (OSError, ValueError):
        logger.exception("could not read avatar for user %s", external_id)
        return False

    if not image_bytes:
        return False

    try:
        ensure_collection()
        result = index_face(image_bytes, external_image_id=external_id)
    except ClientError:
        # InvalidImageFormatException, image too large, no face, etc.
        logger.warning("avatar face indexing failed for user %s", external_id, exc_info=True)
        return False

    indexed = bool(result.get("FaceRecords"))
    if not indexed:
        logger.info("no usable face in avatar for user %s", external_id)
    return indexed
