# app/utils/face_utils.py

import base64
import json
import numpy as np
from PIL import Image
from io import BytesIO
import cv2
from flask import current_app
from app.extensions import db

# تلاش برای import face_recognition
try:
    import face_recognition
    FACE_RECOGNITION_AVAILABLE = True
except ImportError:
    FACE_RECOGNITION_AVAILABLE = False
    print("⚠️ کتابخانه face_recognition نصب نیست. از روش جایگزین استفاده می‌شود.")


def extract_face_encoding_from_image(image_data):
    """
    استخراج بردار ویژگی چهره از تصویر
    """
    try:
        # اگر face_recognition موجود است
        if FACE_RECOGNITION_AVAILABLE:
            return extract_face_encoding_face_recognition(image_data)
        else:
            # استفاده از روش جایگزین با OpenCV
            return extract_face_encoding_opencv(image_data)
            
    except Exception as e:
        print(f"❌ خطا در استخراج بردار ویژگی چهره: {e}")
        return None


def extract_face_encoding_face_recognition(image_data):
    """استخراج با استفاده از face_recognition"""
    try:
        import face_recognition
        import re
        
        # پردازش تصویر
        if isinstance(image_data, str) and image_data.startswith('data:image'):
            image_data = re.sub('^data:image/.+;base64,', '', image_data)
            image_bytes = base64.b64decode(image_data)
            image = Image.open(BytesIO(image_bytes))
            image_np = np.array(image)
            
            # تبدیل به RGB
            if len(image_np.shape) == 3 and image_np.shape[2] == 4:
                image_np = cv2.cvtColor(image_np, cv2.COLOR_RGBA2RGB)
            
            # تشخیص چهره
            face_locations = face_recognition.face_locations(image_np)
            if not face_locations:
                print("❌ هیچ چهره‌ای در تصویر یافت نشد")
                return None
            
            # استخراج بردار ویژگی
            face_encodings = face_recognition.face_encodings(image_np, face_locations)
            if not face_encodings:
                print("❌ بردار ویژگی چهره استخراج نشد")
                return None
            
            return face_encodings[0]
        
        return None
        
    except Exception as e:
        print(f"❌ خطا در extract_face_encoding_face_recognition: {e}")
        return None


def extract_face_encoding_opencv(image_data):
    """استخراج با استفاده از OpenCV (روش جایگزین)"""
    try:
        import re
        
        # پردازش تصویر
        if isinstance(image_data, str) and image_data.startswith('data:image'):
            image_data = re.sub('^data:image/.+;base64,', '', image_data)
            image_bytes = base64.b64decode(image_data)
            image = Image.open(BytesIO(image_bytes))
            image_np = np.array(image)
            
            # تبدیل به RGB
            if len(image_np.shape) == 3 and image_np.shape[2] == 4:
                image_np = cv2.cvtColor(image_np, cv2.COLOR_RGBA2RGB)
            
            # تشخیص چهره با Haar Cascade
            face_cascade = cv2.CascadeClassifier(
                cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
            )
            
            gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
            faces = face_cascade.detectMultiScale(gray, 1.1, 4)
            
            if len(faces) == 0:
                print("❌ هیچ چهره‌ای در تصویر یافت نشد")
                return None
            
            # استفاده از اولین چهره
            (x, y, w, h) = faces[0]
            face_roi = image_np[y:y+h, x:x+w]
            
            # تبدیل به بردار ویژگی ساده (برای تست)
            # در محیط واقعی باید از مدل‌های عمیق مانند FaceNet استفاده شود
            face_encoding = extract_simple_features(face_roi)
            return face_encoding
        
        return None
        
    except Exception as e:
        print(f"❌ خطا در extract_face_encoding_opencv: {e}")
        return None


def extract_simple_features(face_image):
    """استخراج ویژگی‌های ساده از تصویر چهره (برای تست)"""
    try:
        # تبدیل به سایز استاندارد
        face_resized = cv2.resize(face_image, (128, 128))
        
        # تبدیل به خاکستری
        gray = cv2.cvtColor(face_resized, cv2.COLOR_RGB2GRAY)
        
        # محاسبه هیستوگرام
        hist = cv2.calcHist([gray], [0], None, [64], [0, 256])
        hist = hist.flatten()
        hist = hist / np.sum(hist)  # نرمال‌سازی
        
        # محاسبه ویژگی‌های HOG
        hog = cv2.HOGDescriptor()
        hog_features = hog.compute(face_resized)
        hog_features = hog_features.flatten()
        
        # ترکیب ویژگی‌ها
        features = np.concatenate([hist, hog_features[:64]])
        
        # کاهش ابعاد
        if len(features) > 128:
            features = features[:128]
        elif len(features) < 128:
            features = np.pad(features, (0, 128 - len(features)))
        
        return features
        
    except Exception as e:
        print(f"❌ خطا در extract_simple_features: {e}")
        # بازگشت یک بردار تصادفی برای تست
        return np.random.randn(128)


def encode_face_encoding(face_encoding):
    """تبدیل بردار ویژگی به رشته Base64"""
    if face_encoding is None:
        return None
    
    if isinstance(face_encoding, np.ndarray):
        face_encoding = face_encoding.tolist()
    
    encoding_json = json.dumps(face_encoding)
    return base64.b64encode(encoding_json.encode('utf-8')).decode('utf-8')


def decode_face_encoding(encoded_str):
    """تبدیل رشته Base64 به بردار ویژگی"""
    if not encoded_str:
        return None
    
    try:
        decoded = base64.b64decode(encoded_str).decode('utf-8')
        face_encoding = json.loads(decoded)
        return np.array(face_encoding)
    except Exception as e:
        print(f"❌ خطا در دیکود بردار ویژگی چهره: {e}")
        return None


def verify_face(face_data, user_id):
    """
    تشخیص و تایید چهره کاربر
    
    Args:
        face_data: داده‌های تصویر چهره (Base64 یا JSON)
        user_id: شناسه کاربر
    
    Returns:
        bool: موفقیت یا عدم موفقیت
    """
    try:
        from app.models import User
        
        # دریافت کاربر
        user = User.query.get(user_id)
        if not user:
            print(f"❌ کاربر با ID {user_id} یافت نشد")
            return False
        
        # بررسی وجود بردار ویژگی چهره
        if not user.has_face_encoding():
            print(f"⚠️ کاربر {user.fullname} بردار ویژگی چهره ندارد")
            return False
        
        # دریافت بردار ویژگی ذخیره شده
        stored_encoding = user.get_face_encoding()
        if stored_encoding is None:
            print(f"❌ خطا در دریافت بردار ویژگی چهره کاربر {user.fullname}")
            return False
        
        # استخراج بردار ویژگی از تصویر جدید
        new_encoding = extract_face_encoding_from_image(face_data)
        if new_encoding is None:
            print("❌ خطا در استخراج بردار ویژگی از تصویر جدید")
            return False
        
        # اگر face_recognition موجود است
        if FACE_RECOGNITION_AVAILABLE:
            import face_recognition
            distance = face_recognition.face_distance([stored_encoding], new_encoding)[0]
            threshold = user.get_face_threshold()
            
            print(f"🔍 فاصله چهره: {distance:.4f} (آستانه: {threshold})")
            
            if distance <= threshold:
                # تایید موفق
                user.face_verified_at = datetime.utcnow()
                user.reset_face_attempts()
                db.session.commit()
                print(f"✅ چهره کاربر {user.fullname} با موفقیت تایید شد")
                return True
            else:
                # تایید ناموفق
                user.increment_face_attempts()
                db.session.commit()
                print(f"❌ چهره کاربر {user.fullname} تایید نشد. فاصله: {distance:.4f}")
                return False
        
        else:
            # روش جایگزین: مقایسه ساده
            # محاسبه شباهت با استفاده از فاصله اقلیدسی
            distance = np.linalg.norm(stored_encoding - new_encoding)
            threshold = user.get_face_threshold() * 10  # تنظیم آستانه برای روش جایگزین
            
            print(f"🔍 فاصله چهره: {distance:.4f} (آستانه: {threshold})")
            
            if distance <= threshold:
                user.face_verified_at = datetime.utcnow()
                user.reset_face_attempts()
                db.session.commit()
                print(f"✅ چهره کاربر {user.fullname} با موفقیت تایید شد")
                return True
            else:
                user.increment_face_attempts()
                db.session.commit()
                print(f"❌ چهره کاربر {user.fullname} تایید نشد. فاصله: {distance:.4f}")
                return False
            
    except Exception as e:
        print(f"❌ خطا در تشخیص چهره: {e}")
        import traceback
        traceback.print_exc()
        return False


def save_face_encoding(user, image_data):
    """
    ذخیره بردار ویژگی چهره کاربر
    
    Args:
        user: مدل User
        image_data: داده تصویر
    
    Returns:
        bool: موفقیت یا عدم موفقیت
    """
    try:
        face_encoding = extract_face_encoding_from_image(image_data)
        if face_encoding is None:
            return False
        
        user.set_face_encoding(face_encoding)
        db.session.commit()
        print(f"✅ بردار ویژگی چهره برای کاربر {user.fullname} ذخیره شد")
        return True
        
    except Exception as e:
        print(f"❌ خطا در ذخیره بردار ویژگی چهره: {e}")
        db.session.rollback()
        return False


def compare_faces(encoding1, encoding2, threshold=0.6):
    """
    مقایسه دو بردار ویژگی چهره
    
    Args:
        encoding1: بردار ویژگی اول
        encoding2: بردار ویژگی دوم
        threshold: آستانه تشخیص
    
    Returns:
        tuple: (موفقیت, فاصله)
    """
    try:
        if FACE_RECOGNITION_AVAILABLE:
            import face_recognition
            distance = face_recognition.face_distance([encoding1], encoding2)[0]
            return distance <= threshold, distance
        else:
            distance = np.linalg.norm(encoding1 - encoding2)
            threshold_adj = threshold * 10
            return distance <= threshold_adj, distance
            
    except Exception as e:
        print(f"❌ خطا در مقایسه چهره‌ها: {e}")
        return False, 1.0