#!/opt/homebrew/bin/python3.11
"""
Update person demographics (Age, Gender) using InsightFace.
This script scans the representative face of each person and updates the DB.
"""

import os
import cv2
import json
import psycopg2
import numpy as np
import insightface
from insightface.app import FaceAnalysis

# Configuration
DB_CONFIG = {"host": "localhost", "user": "accusys", "dbname": "momentry"}
VIDEO_PATH = "output/384b0ff44aaaa1f1/384b0ff44aaaa1f1.mp4"


def get_face_app():
    app = FaceAnalysis(name="buffalo_l", providers=["CPUExecutionProvider"])
    app.prepare(ctx_id=0, det_size=(640, 640))
    return app


def get_person_frames(conn):
    """Get one frame timestamp for each person."""
    cur = conn.cursor()
    # Get the first appearance time for each person to save processing time
    cur.execute("""
        SELECT person_id, MIN(start_time) as start_time 
        FROM dev.person_appearances 
        GROUP BY person_id
    """)
    return cur.fetchall()


def get_frame_at_time(video_path, time_sec):
    """Extract a single frame from video."""
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        return None

    # InsightFace expects BGR (OpenCV default), but we need to seek correctly
    # cv2 CAP_PROP_POS_MSEC is sometimes inaccurate, better to use FPS if known
    # But for a "representative" frame, seeking by ms is usually "good enough"
    cap.set(cv2.CAP_PROP_POS_MSEC, time_sec * 1000)
    ret, frame = cap.read()
    cap.release()

    if ret:
        return frame
    return None


def analyze_face(app, frame):
    """Run InsightFace to get age/gender."""
    faces = app.get(frame)
    if faces:
        # Just take the first face found
        face = faces[0]
        age = int(face.age) if hasattr(face, "age") else None
        gender = (
            "female"
            if (hasattr(face, "gender") and face.gender == 0)
            else ("male" if (hasattr(face, "gender") and face.gender == 1) else None)
        )
        return age, gender
    return None, None


def update_person_db(conn, person_id, age, gender):
    """Update DB."""
    cur = conn.cursor()
    cur.execute(
        """
        UPDATE dev.person_identities 
        SET age = %s, gender = %s 
        WHERE person_id = %s
    """,
        (age, gender, person_id),
    )
    conn.commit()


def main():
    print("=== Person Demographics Updater ===")

    # 1. Init DB
    conn = psycopg2.connect(**DB_CONFIG)

    # 2. Init Model
    print("Loading InsightFace model...")
    app = get_face_app()

    # 3. Get List
    persons = get_person_frames(conn)
    print(f"Found {len(persons)} persons to process.")

    for i, (person_id, start_time) in enumerate(persons):
        print(
            f"Processing {i + 1}/{len(persons)}: {person_id} (Time: {start_time:.1f}s)"
        )

        # 4. Get Frame
        frame = get_frame_at_time(VIDEO_PATH, start_time)

        if frame is not None:
            # 5. Analyze
            age, gender = analyze_face(app, frame)

            if age and gender:
                print(f"  -> Detected: Age {age}, Gender {gender}")
                # 6. Update
                update_person_db(conn, person_id, age, gender)
            else:
                print(f"  -> Face not found or attributes missing in this frame.")
        else:
            print(f"  -> Failed to retrieve frame.")

    print("=== Done ===")
    conn.close()


if __name__ == "__main__":
    main()
