import cv2
from src.models.model_ia import analizar_frames_con_openai,analizar_frames_con_openai_uno,analizar_frames_con_openai_varios
import json
import re
import numpy as np
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
from src.validators.deteccion import (
    detectar_rostro,
    detectar_ojos,
    evaluar_iluminacion,
    detectar_labios,
    estimar_parpadeo,
    estimar_mov_labios,
    estimar_lentes,estimar_auriculares
)


# === Función principal con procesamiento local + LHIA ===


def sanitizar_json_no_estricto(texto):
    # Agrega comillas dobles a claves sin comillas
    return re.sub(r'(?<!")(\b\w+\b)(?=\s*:)', r'"\1"', texto)



def recortar_rostro_con_contornos(frame: np.ndarray) -> np.ndarray:
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    rostros = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)

    for (x, y, w, h) in rostros:
        rostro = frame[y:y+h, x:x+w]
        gray_rostro = cv2.cvtColor(rostro, cv2.COLOR_BGR2GRAY)

        # Eliminar fondo con contornos
        _, thresh = cv2.threshold(gray_rostro, 60, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
        contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        mask = np.zeros_like(rostro)
        cv2.drawContours(mask, contours, -1, (255, 255, 255), thickness=cv2.FILLED)

        rostro_con_mask = cv2.bitwise_and(rostro, mask)
        return cv2.resize(rostro_con_mask, (224, 224))

    return None

def procesar_prueba_vida_avanzada(video_path: str) -> dict:
    cap = cv2.VideoCapture(video_path)
    total_frames = 0
    frame_openai_1 = None
    frame_openai_2 = None
    rostros = 0

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        total_frames += 1

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        rostro = detectar_rostro(gray)

        if rostro is not None:
            rostros += 1

        if total_frames == 3:
            frame_openai_1 = recortar_rostro_con_contornos(frame)
        if total_frames == 6:
            frame_openai_2 = recortar_rostro_con_contornos(frame)

    cap.release()

    openai_resultado = {}

    if frame_openai_1 is not None and frame_openai_2 is not None:
        try:
            resultado_openai = analizar_frames_con_openai(frame_openai_1, frame_openai_2).strip()
            match = re.search(r"{[\s\S]*?}", resultado_openai)
            resultado_limpio = match.group(0) if match else resultado_openai

            try:
                openai_resultado = json.loads(resultado_limpio)
            except json.JSONDecodeError:
                json_corr = sanitizar_json_no_estricto(resultado_limpio)
                openai_resultado = json.loads(json_corr)

        except Exception as e:
            openai_resultado = {
                "error_lhia": str(e),
                "raw": locals().get("resultado_limpio", "")
            }

    return {
        "resultado_vida": openai_resultado
    }

##def procesar_prueba_vida_avanzada_one_frame(video_path: str) -> dict:
##    cap = cv2.VideoCapture(video_path)
##
##    # Obtener FPS del video
##    fps = cap.get(cv2.CAP_PROP_FPS)
##    if not fps or fps == 0:
##        return {"resultado_vida": {"error": "No se pudo obtener FPS del video."}}
##
##    # Calcular el número de frame correspondiente a los 2.5 segundos
##    frame_target = int(fps * 2.5)
##    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_target)
##
##    ret, frame = cap.read()
##    cap.release()
##
##    openai_resultado = {}
##
##    if ret:
##        # Detectar rostro antes de enviar
##        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
##        rostro = detectar_rostro(gray)
##        if rostro is not None:
##            frame_openai = recortar_rostro_con_contornos(frame)
##
##            try:
##                resultado_openai = analizar_frames_con_openai_uno(frame_openai).strip()
##                match = re.search(r"{[\s\S]*?}", resultado_openai)
##                resultado_limpio = match.group(0) if match else resultado_openai
##
##                try:
##                    openai_resultado = json.loads(resultado_limpio)
##                except json.JSONDecodeError:
##                    json_corr = sanitizar_json_no_estricto(resultado_limpio)
##                    openai_resultado = json.loads(json_corr)
##
##            except Exception as e:
##                openai_resultado = {
##                    "error_lhia": str(e),
##                    "raw": locals().get("resultado_limpio", "")
##                }
##        else:
##            openai_resultado = {
##                "error": "No se detectó rostro en el frame capturado en el segundo 2.5"
##            }
##    else:
##        openai_resultado = {
##            "error": "No se pudo leer el frame en el segundo 2.5"
##        }
##
##    return {
##        "resultado_vida": openai_resultado,
##    }


def procesar_prueba_vida_avanzada_one_frame(video_path: str) -> dict:
    cap = cv2.VideoCapture(video_path)

    fps = cap.get(cv2.CAP_PROP_FPS)
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    duracion = total_frames / fps if fps > 0 else 0

    fps = cap.get(cv2.CAP_PROP_FPS)
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    duracion = total_frames / fps if fps > 0 else 0
    
    if not fps or fps == 0:
        return {"resultado_vida": {"error": "No se pudo obtener FPS del video."}}
    
    # Calcular tiempos, aunque el video sea corto
    tiempos_objetivo = sorted(set([
        min(duracion * 0.2, duracion - 0.1),
        min(duracion * 0.5, duracion - 0.05),
        max(duracion - 0.1, 0.1)
    ]))

    frames_recortados = []

    for tiempo in tiempos_objetivo:
        frame_target = int(fps * tiempo)
        cap.set(cv2.CAP_PROP_POS_FRAMES, frame_target)
        ret, frame = cap.read()

        if not ret:
            continue

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        rostro = detectar_rostro(gray)

        if rostro is not None:
            frame_recortado = recortar_rostro_con_contornos(frame)
        else:
            h, w, _ = frame.shape
            center_crop = frame[h//4:h*3//4, w//4:w*3//4]
            frame_recortado = cv2.resize(center_crop, (256, 256))

        frames_recortados.append(frame_recortado)
        cv2.imwrite(f"frame_debug_{len(frames_recortados)}.jpg", frame_recortado)

    cap.release()

    while len(frames_recortados) < 3:
        frames_recortados.append(np.zeros((256, 256, 3), dtype=np.uint8))

    try:
        resultado_openai = analizar_frames_con_openai_varios(
            frames_recortados[0], frames_recortados[1], frames_recortados[2]
        ).strip()

        match = re.search(r"{[\s\S]*?}", resultado_openai)
        resultado_limpio = match.group(0) if match else resultado_openai

        try:
            openai_resultado = json.loads(resultado_limpio)
        except json.JSONDecodeError:
            json_corr = sanitizar_json_no_estricto(resultado_limpio)
            openai_resultado = json.loads(json_corr)

    except Exception as e:
        openai_resultado = {
            "error_lhia": str(e),
            "raw": locals().get("resultado_limpio", "")
        }

    return {
        "resultado_vida": openai_resultado,
    }
