from flask import Flask, request, jsonify, make_response
from flask_cors import CORS
import os
import base64
import cv2
import numpy as np
import json
import datetime
import requests
import urllib3

# Disable SSL warnings for API calls
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from livestream import train_face_recognizer, preprocess_face

# InsightFace imports with error handling
try:
    import insightface
    import onnxruntime
    import pickle
    INSIGHTFACE_AVAILABLE = True
    print("✅ InsightFace libraries loaded successfully")
except ImportError as e:
    INSIGHTFACE_AVAILABLE = False
    print(f"⚠️ InsightFace not available: {e}")
    print("📝 System will continue with OpenCV only")

app = Flask(__name__)
# CORS policy for Fran
CORS(app, 
     origins=['https://fran-dev.scrubbed.net', 'https://fran.scrubbed.net', 'http://localhost:8081', 'http://localhost:3000', 'http://localhost:5173'],
     supports_credentials=True,
     methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
     allow_headers=['Content-Type', 'x-access-token', 'Authorization'])

FACE_DIR = "registered_faces"
API_ENDPOINT = "https://api-hris.scrubbed.net/users/getUserInfo"
SETTINGS_FILE = "app_settings.json"

# Global InsightFace model (initialized once)
insightface_model = None

# Default settings
DEFAULT_SETTINGS = {
    "recognition_library": "insightface",  # Default to InsightFace
    "insightface_threshold": 0.6,
    "opencv_threshold": 100
}

def load_settings():
    """Load application settings from file"""
    try:
        if os.path.exists(SETTINGS_FILE):
            with open(SETTINGS_FILE, 'r') as f:
                settings = json.load(f)
                # Merge with defaults to ensure all keys exist
                for key, value in DEFAULT_SETTINGS.items():
                    if key not in settings:
                        settings[key] = value
                return settings
        else:
            return DEFAULT_SETTINGS.copy()
    except Exception as e:
        print(f"⚠️ Error loading settings: {e}")
        return DEFAULT_SETTINGS.copy()

def save_settings(settings):
    """Save application settings to file"""
    try:
        with open(SETTINGS_FILE, 'w') as f:
            json.dump(settings, f, indent=2)
        print(f"✅ Settings saved: {settings}")
        return True
    except Exception as e:
        print(f"❌ Error saving settings: {e}")
        return False

def initialize_insightface():
    """Initialize InsightFace model globally"""
    global insightface_model
    if not INSIGHTFACE_AVAILABLE:
        return False
    
    try:
        if insightface_model is None:
            insightface_model = insightface.app.FaceAnalysis()
            insightface_model.prepare(ctx_id=0, det_size=(640, 640))
            print("✅ InsightFace model initialized successfully")
        return True
    except Exception as e:
        print(f"❌ Error initializing InsightFace model: {e}")
        return False

def generate_insightface_embeddings(user_id, user_folder):
    """Generate InsightFace embeddings for user images"""
    if not INSIGHTFACE_AVAILABLE:
        print("⚠️ InsightFace not available, skipping embedding generation")
        return False
    
    try:
        # Initialize model if not already done
        if not initialize_insightface():
            return False
        
        embeddings = []
        image_files = [f for f in os.listdir(user_folder) if f.endswith('.jpg')]
        
        print(f"🔄 Processing {len(image_files)} images for InsightFace embeddings...")
        
        for img_file in image_files:
            img_path = os.path.join(user_folder, img_file)
            img = cv2.imread(img_path)
            
            if img is not None:
                faces = insightface_model.get(img)
                if faces:
                    # Use first detected face
                    embedding = faces[0].embedding
                    embeddings.append(embedding)
                    print(f"✅ Generated embedding for {img_file}")
                else:
                    print(f"⚠️ No face detected in {img_file}")
            else:
                print(f"❌ Could not read image {img_file}")
        
        if embeddings:
            # Save embeddings to pickle file
            embedding_data = {
                'user_id': user_id,
                'embeddings': embeddings,
                'created_at': datetime.datetime.now().isoformat(),
                'image_count': len(embeddings)
            }
            
            embedding_file = f"insightface_embeddings_{user_id}.pkl"
            with open(embedding_file, 'wb') as f:
                pickle.dump(embedding_data, f)
            
            print(f"✅ Generated {len(embeddings)} InsightFace embeddings for user {user_id}")
            print(f"💾 Saved embeddings to {embedding_file}")
            return True
        else:
            print(f"⚠️ No faces detected in any images for user {user_id}")
            return False
            
    except Exception as e:
        print(f"❌ Error generating InsightFace embeddings: {e}")
        return False

def fetch_employee_info(user_id):
    """Fetch employee information from live API endpoint"""
    try:
        # Use GET request with user_id in URL path
        url = f"{API_ENDPOINT}/{user_id}"
        headers = {"Content-Type": "application/json"}
        
        response = requests.get(url, headers=headers, timeout=10, verify=False)
        
        if response.status_code == 200:
            # Parse the response to extract employee information
            response_data = response.json()
            
            # Extract employee details from API response
            employee_info = {
                'user_id': str(user_id),
                'name': response_data.get('name', f'User {user_id}'),
                'email': response_data.get('email', ''),
                'department': response_data.get('department', ''),
                'status': response_data.get('status', 'active'),
                'api_response': response_data  # Keep full response for debugging
            }
            
            print(f"✅ Fetched employee info for User {user_id}: {employee_info['name']} - {employee_info['department']}")
            return employee_info
            
        else:
            print(f"⚠️ API request failed for User {user_id}. Status: {response.status_code}, Response: {response.text}")
            return {
                'user_id': str(user_id),
                'name': f'User {user_id}',
                'email': '',
                'department': '',
                'status': 'unknown',
                'api_response': None
            }
            
    except requests.exceptions.RequestException as e:
        print(f"❌ Error fetching employee info for User {user_id}: {e}")
        return {
            'user_id': str(user_id),
            'name': f'User {user_id}',
            'email': '',
            'department': '',
            'status': 'unknown',
            'api_response': None
        }

@app.route('/register', methods=['POST'])
def register():
    data = request.get_json()
    user_id = data.get('userId')
    images = data.get('images')

    if not user_id or not images:
        return jsonify({'error': 'User ID and images are required'}), 400

    # Fetch employee info to get the name and other details
    employee_info = fetch_employee_info(user_id)
    if not employee_info or employee_info.get('status') == 'unknown':
        return jsonify({'error': f'Could not retrieve information for User ID {user_id}. Please check the ID and try again.'}), 404

    user_name = employee_info.get('name')
    user_email = employee_info.get('email')
    user_department = employee_info.get('department')

    user_folder = os.path.join(FACE_DIR, user_id)
    os.makedirs(user_folder, exist_ok=True)

    for i, image_data in enumerate(images):
        # Decode the base64 image
        header, encoded = image_data.split(',', 1)
        image_bytes = base64.b64decode(encoded)
        
        # Save the image
        with open(os.path.join(user_folder, f'{i}.jpg'), 'wb') as f:
            f.write(image_bytes)

    # Train the model after saving the images
    print("Starting training process...")
    print(f"Training with {len(images)} images for user {user_id}")
    train_face_recognizer()
    print("Training process finished.")
    
    # Verify training worked by checking model file
    if os.path.exists("face_recognizer.yml"):
        print("Model file updated successfully")
    else:
        print("WARNING: Model file not found after training")
    
    # Generate InsightFace embeddings if available
    if INSIGHTFACE_AVAILABLE:
        print("🔄 Generating InsightFace embeddings...")
        insightface_success = generate_insightface_embeddings(user_id, user_folder)
        if insightface_success:
            print("✅ InsightFace embedding generation completed")
        else:
            print("⚠️ InsightFace embedding generation failed")
    else:
        print("📝 InsightFace not available, skipping embedding generation")
    
    # Save user data to JSON before deleting photos
    user_data_file = "user_data.json"
    user_data = {}
    if os.path.exists(user_data_file):
        with open(user_data_file, 'r') as f:
            user_data = json.load(f)
    
    # Add/update user data
    user_data[user_id] = {
        'name': user_name,
        'email': user_email,
        'department': user_department,
        'status': 'hired',
        'last_updated': datetime.datetime.now().isoformat()
    }
    
    with open(user_data_file, 'w') as f:
        json.dump(user_data, f, indent=2)
    
    # Keep photos temporarily for better training (delete after 5 minutes for security)
    print("Photos kept temporarily for training verification...")
    print("Photos will be automatically deleted after 5 minutes for security.")
    
    # Schedule photo deletion after 5 minutes
    import threading
    import shutil
    def delete_photos_later():
        import time
        time.sleep(300)  # 5 minutes
        if os.path.exists(user_folder):
            shutil.rmtree(user_folder)
            print(f"Photos for user {user_id} deleted after 5 minutes for security.")
    
    # Start deletion timer in background
    deletion_thread = threading.Thread(target=delete_photos_later)
    deletion_thread.daemon = True
    deletion_thread.start()

    return jsonify({'message': f'User {user_id} ({user_name}) registered successfully with {len(images)} images. Photos deleted for security.'})

@app.route('/recognize', methods=['POST'])
def recognize_face():
    """Main recognition endpoint that routes to the appropriate library based on settings"""
    data = request.get_json()
    image_data = data.get('image')
    
    if not image_data:
        return jsonify({'error': 'Image data is required'}), 400
    
    try:
        # Load settings to determine which library to use
        settings = load_settings()
        library = settings.get('recognition_library', 'insightface')
        
        print(f"🔍 Using recognition library: {library}")
        
        # Route to appropriate recognition method
        if library == 'insightface' and INSIGHTFACE_AVAILABLE:
            # Use InsightFace recognition
            return insightface_recognize()
        else:
            # Use OpenCV recognition (fallback or explicit choice)
            return opencv_recognize()
            
    except Exception as e:
        print(f"❌ Error in main recognition endpoint: {e}")
        return jsonify({'error': str(e)}), 500

def opencv_recognize():
    """OpenCV-based face recognition"""
    data = request.get_json()
    image_data = data.get('image')
    
    try:
        # Decode the base64 image
        header, encoded = image_data.split(',', 1)
        image_bytes = base64.b64decode(encoded)
        
        # Convert to numpy array
        nparr = np.frombuffer(image_bytes, np.uint8)
        img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        
        if img is None:
            return jsonify({'error': 'Invalid image data'}), 400
        
        # Convert to grayscale
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        
        # Load face cascade
        face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
        
        # Detect faces with more sensitive parameters for better detection
        faces = face_cascade.detectMultiScale(gray, scaleFactor=1.05, minNeighbors=3, minSize=(20, 20))
        
        print(f"🔍 OpenCV Face detection: Found {len(faces)} faces in image")
        print(f"📐 Image size: {img.shape}")
        
        if len(faces) == 0:
            print("❌ No faces detected - returning 400 error")
            return jsonify({'error': 'No face detected'}), 400
        
        # Get the first detected face
        (x, y, w, h) = faces[0]
        face_img = gray[y:y + h, x:x + w]
        face_img = preprocess_face(face_img)
        
        # Load and use the recognizer
        try:
            recognizer = cv2.face.LBPHFaceRecognizer_create()
            model_file = "face_recognizer.yml"
            
            if not os.path.exists(model_file):
                return jsonify({'error': 'Model file not found. Train the model first.'}), 400
            
            recognizer.read(model_file)
            user_id, confidence = recognizer.predict(face_img)
            
            # Load settings to get OpenCV threshold
            settings = load_settings()
            confidence_threshold = settings.get('opencv_threshold', 150)  # Lower is better in LBPH
            print(f"🔍 Using OpenCV threshold: {confidence_threshold}")
            
            print(f"Recognition attempt - User ID: {user_id}, Confidence: {confidence}, Threshold: {confidence_threshold}")
            print(f"Recognition result: {'SUCCESS' if confidence < confidence_threshold else 'FAILED'}")
            
            if confidence < confidence_threshold:
                # Fetch employee information from live API endpoint
                print(f"✅ RECOGNITION SUCCESS: User {user_id} recognized with confidence {confidence}")
                print(f"🔄 Fetching employee information for User {user_id} from live API...")
                employee_info = fetch_employee_info(user_id)
                print(f"📋 Employee info result: {employee_info}")
                
                # Log attendance with employee information
                import datetime
                import csv
                
                now = datetime.datetime.now()
                timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
                today = now.strftime("%Y-%m-%d")
                
                log_file = "attendance_log.csv"
                
                # Ensure log file exists with headers
                if not os.path.exists(log_file) or os.stat(log_file).st_size == 0:
                    with open(log_file, "w", newline="") as file:
                        writer = csv.writer(file)
                        writer.writerow(["Timestamp", "User ID", "User Name", "Status"])
                
                attendance_status = "Check-in"  # Default
                message = f'User {employee_info["name"]} (ID: {user_id}) checked in successfully'
                
                all_records = []
                today_records = []
                
                with open(log_file, 'r', newline='') as file:
                    reader = csv.DictReader(file)
                    for row in reader:
                        all_records.append(row)
                        if row.get('User ID') == str(user_id) and row.get('Timestamp', '').startswith(today):
                            today_records.append(row)
                
                # Determine attendance status based on today's records
                check_in_exists = any(r.get('Status') == 'Check-in' for r in today_records)
                check_out_exists = any(r.get('Status') == 'Check-out' for r in today_records)
                
                if not check_in_exists:
                    # First recognition today - Check-in
                    attendance_status = "Check-in"
                    message = f'User {employee_info["name"]} (ID: {user_id}) checked in successfully'
                    all_records.append({'Timestamp': timestamp, 'User ID': str(user_id), 'User Name': employee_info["name"], 'Status': attendance_status})
                elif check_in_exists and not check_out_exists:
                    # Second recognition today - Check-out
                    attendance_status = "Check-out"
                    message = f'User {employee_info["name"]} (ID: {user_id}) checked out successfully'
                    all_records.append({'Timestamp': timestamp, 'User ID': str(user_id), 'User Name': employee_info["name"], 'Status': attendance_status})
                elif check_in_exists and check_out_exists:
                    # Third+ recognition today - Update latest checkout
                    attendance_status = "Check-out"
                    message = f'User {employee_info["name"]} (ID: {user_id}) checkout time updated'
                    
                    # Find and update the last checkout record for today
                    for i in reversed(range(len(all_records))):
                        record = all_records[i]
                        if record.get('User ID') == str(user_id) and record.get('Timestamp', '').startswith(today) and record.get('Status') == 'Check-out':
                            record['Timestamp'] = timestamp # Update timestamp
                            record['User Name'] = employee_info["name"] # Also update the name
                            break
                    else: # If no checkout record found (shouldn't happen with logic above, but as fallback)
                        all_records.append({'Timestamp': timestamp, 'User ID': str(user_id), 'User Name': employee_info["name"], 'Status': attendance_status})
                
                # Write all records back to the file
                with open(log_file, "w", newline="") as file:
                    writer = csv.DictWriter(file, fieldnames=["Timestamp", "User ID", "User Name", "Status"])
                    writer.writeheader()
                    writer.writerows(all_records)
                
                response_data = {
                    'success': True,
                    'user_id': int(user_id),
                    'user_name': employee_info["name"],
                    'user_email': employee_info["email"],
                    'user_department': employee_info["department"],
                    'user_status': employee_info["status"],
                    'confidence': round(confidence, 2),
                    'timestamp': timestamp,
                    'attendance_status': attendance_status,
                    'message': message
                }
                print(f"📤 Sending response to frontend: {response_data}")
                return jsonify(response_data)
            else:
                return jsonify({
                    'success': False,
                    'message': 'Face not recognized',
                    'confidence': round(confidence, 2),
                    'debug_info': f'Confidence {confidence} >= threshold {confidence_threshold}'
                })
                
        except Exception as e:
            return jsonify({'error': f'Recognition error: {str(e)}'}), 500
            
    except Exception as e:
                    return jsonify({'error': f'Image processing error: {str(e)}'}), 500

@app.route('/admin/users', methods=['GET'])
def get_all_users():
    """Get all registered users with their details (photos deleted for security)"""
    try:
        users = []
        
        # Read user data from JSON file (photos are deleted for security)
        user_data_file = "user_data.json"
        user_data = {}
        if os.path.exists(user_data_file):
            with open(user_data_file, 'r') as f:
                user_data = json.load(f)
        
        for user_id, user_info in user_data.items():
            # Check if user has recent attendance
            attendance_file = "attendance_log.csv"
            last_attendance = None
            if os.path.exists(attendance_file):
                with open(attendance_file, 'r') as f:
                    lines = f.readlines()
                    for line in reversed(lines):
                        if line.strip() and user_id in line:
                            last_attendance = line.split(',')[0].strip()
                            break
            
            users.append({
                'user_id': user_id,
                'name': user_info.get('name', 'Unknown'),
                'email': user_info.get('email', ''),
                'department': user_info.get('department', ''),
                'image_count': 'Trained',  # Photos deleted for security
                'last_modified': user_info.get('last_updated', ''),
                'last_attendance': last_attendance,
                'status': 'Active',  # All users in JSON are active (trained)
                "data" : user_info
            })
        
        # Sort by last updated (newest first)
        users.sort(key=lambda x: x['last_modified'], reverse=True)
        
        return jsonify({'users': users})
    except Exception as e:
        return jsonify({'error': f'Error fetching users: {str(e)}'}), 500

@app.route('/admin/users/<user_id>', methods=['DELETE'])
def delete_user(user_id):
    """Delete a user from the system and retrain model"""
    try:
        # Remove user from JSON data
        user_data_file = "user_data.json"
        user_deleted = False
        
        if os.path.exists(user_data_file):
            with open(user_data_file, 'r') as f:
                user_data = json.load(f)
            
            if user_id in user_data:
                del user_data[user_id]
                user_deleted = True
                
                with open(user_data_file, 'w') as f:
                    json.dump(user_data, f, indent=2)
        
        # Remove any remaining photo folders for this user
        user_folder = os.path.join(FACE_DIR, user_id)
        if os.path.exists(user_folder):
            import shutil
            shutil.rmtree(user_folder)
            user_deleted = True
        
        if user_deleted:
            # Retrain the model to remove the deleted user's data
            print(f"Retraining model after deleting user {user_id}...")
            train_face_recognizer()
            print("Model retrained successfully.")
            
            return jsonify({'message': f'User {user_id} deleted successfully from system and model retrained.'})
        else:
            return jsonify({'error': 'User not found in system'}), 404
    except Exception as e:
        return jsonify({'error': f'Error deleting user: {str(e)}'}), 500

@app.route('/admin/users/<old_user_id>', methods=['PUT'])
def update_user_id(old_user_id):
    """Update user ID (rename folder)"""
    try:
        old_folder = os.path.join(FACE_DIR, old_user_id)
        new_folder = os.path.join(FACE_DIR, new_user_id)
        
        if not os.path.exists(old_folder):
            return jsonify({'error': 'User not found'}), 404
        
        data = request.get_json()
        new_user_id = data.get('new_user_id')
        
        if not new_user_id:
            return jsonify({'error': 'New user ID is required'}), 400
        
        new_folder = os.path.join(FACE_DIR, new_user_id)
        
        if os.path.exists(new_folder):
            return jsonify({'error': 'New user ID already exists'}), 400
        
        os.rename(old_folder, new_folder)
        
        # Note: No retraining needed - photos are deleted for security reasons
        # The trained model retains the user's face data without storing raw images
        
        return jsonify({'message': f'User ID updated from {old_user_id} to {new_user_id}'})
    except Exception as e:
        return jsonify({'error': f'Error updating user ID: {str(e)}'}), 500

@app.route('/admin/users/<user_id>/images', methods=['DELETE'])
def delete_user_images(user_id):
    """Delete all images for a user but keep the folder"""
    try:
        user_folder = os.path.join(FACE_DIR, user_id)
        if not os.path.exists(user_folder):
            return jsonify({'error': 'User not found'}), 404
        
        # Delete all jpg files
        deleted_count = 0
        for filename in os.listdir(user_folder):
            if filename.endswith('.jpg'):
                os.remove(os.path.join(user_folder, filename))
                deleted_count += 1
        
        # Note: No retraining needed - photos are deleted for security reasons
        # The trained model retains the user's face data without storing raw images
        
        return jsonify({'message': f'Deleted {deleted_count} images for user {user_id}'})
    except Exception as e:
        return jsonify({'error': f'Error deleting images: {str(e)}'}), 500

@app.route('/admin/users/<user_id>/images', methods=['GET'])
def get_user_images(user_id):
    """Get all images for a specific user"""
    try:
        user_folder = os.path.join(FACE_DIR, user_id)
        
        # Check if user exists in user_data.json
        user_data_file = "user_data.json"
        user_exists = False
        if os.path.exists(user_data_file):
            with open(user_data_file, 'r') as f:
                user_data = json.load(f)
                user_exists = user_id in user_data
        
        if not user_exists:
            return jsonify({'error': 'User not found'}), 404
        
        # If folder doesn't exist, images were deleted for security
        if not os.path.exists(user_folder):
            return jsonify({
                'images': [],
                'message': 'Images deleted for security after training',
                'status': 'trained'
            })
        
        images = []
        for filename in os.listdir(user_folder):
            if filename.endswith('.jpg'):
                image_path = os.path.join(user_folder, filename)
                # Convert image to base64
                with open(image_path, 'rb') as f:
                    image_data = base64.b64encode(f.read()).decode('utf-8')
                    images.append({
                        'filename': filename,
                        'data': f'data:image/jpeg;base64,{image_data}'
                    })
        
        return jsonify({'images': images})
    except Exception as e:
        return jsonify({'error': f'Error fetching images: {str(e)}'}), 500

@app.route('/admin/settings', methods=['GET'])
def get_admin_settings():
    """Get current admin settings"""
    try:
        settings = load_settings()
        return jsonify({
            'success': True,
            'settings': settings,
            'available_libraries': {
                'opencv': {
                    'name': 'OpenCV LBPH',
                    'accuracy': '70-80%',
                    'description': 'Traditional computer vision approach'
                },
                'insightface': {
                    'name': 'InsightFace',
                    'accuracy': '98%+',
                    'description': 'State-of-the-art deep learning model',
                    'available': INSIGHTFACE_AVAILABLE
                }
            }
        })
    except Exception as e:
        return jsonify({'error': f'Error loading settings: {str(e)}'}), 500

@app.route('/admin/settings', methods=['POST'])
def update_admin_settings():
    """Update admin settings"""
    try:
        data = request.get_json()
        if not data:
            return jsonify({'error': 'No data provided'}), 400
        
        current_settings = load_settings()
        
        # Validate recognition library
        if 'recognition_library' in data:
            library = data['recognition_library']
            if library not in ['opencv', 'insightface']:
                return jsonify({'error': 'Invalid recognition library. Must be "opencv" or "insightface"'}), 400
            
            # Check if InsightFace is available when trying to use it
            if library == 'insightface' and not INSIGHTFACE_AVAILABLE:
                return jsonify({
                    'error': 'InsightFace is not available. Please install InsightFace libraries or use OpenCV.',
                    'available_libraries': ['opencv']
                }), 400
        
        # Validate thresholds
        if 'insightface_threshold' in data:
            threshold = data['insightface_threshold']
            if not isinstance(threshold, (int, float)) or not (0.0 <= threshold <= 1.0):
                return jsonify({'error': 'InsightFace threshold must be between 0.0 and 1.0'}), 400
        
        if 'opencv_threshold' in data:
            threshold = data['opencv_threshold']
            if not isinstance(threshold, (int, float)) or threshold < 0:
                return jsonify({'error': 'OpenCV threshold must be a positive number'}), 400
        
        # Update settings
        current_settings.update(data)
        
        # Save settings
        if save_settings(current_settings):
            return jsonify({
                'success': True,
                'message': 'Settings updated successfully',
                'settings': current_settings
            })
        else:
            return jsonify({'error': 'Failed to save settings'}), 500
            
    except Exception as e:
        return jsonify({'error': f'Error updating settings: {str(e)}'}), 500

@app.route('/attendance/stats', methods=['GET'])
def get_attendance_stats():
    """Get attendance statistics for dashboard"""
    try:
        import datetime
        import csv
        from collections import defaultdict
        
        today = datetime.datetime.now().strftime("%Y-%m-%d")
        week_ago = (datetime.datetime.now() - datetime.timedelta(days=7)).strftime("%Y-%m-%d")
        month_ago = (datetime.datetime.now() - datetime.timedelta(days=30)).strftime("%Y-%m-%d")
        
        # Initialize stats
        stats = {
            'today': 0,
            'thisWeek': 0,
            'thisMonth': 0,
            'recentActivity': []
        }
        
        # Read attendance log if it exists
        log_file = "attendance_log.csv"
        if os.path.exists(log_file):
            with open(log_file, 'r', newline='') as file:
                reader = csv.DictReader(file)
                for row in reader:
                    timestamp = row.get('Timestamp', '')
                    if timestamp:
                        try:
                            # Parse timestamp
                            dt = datetime.datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
                            date_str = dt.strftime("%Y-%m-%d")
                            
                            # Count today's check-ins
                            if date_str == today:
                                stats['today'] += 1
                            
                            # Count this week's check-ins
                            if date_str >= week_ago:
                                stats['thisWeek'] += 1
                            
                            # Count this month's check-ins
                            if date_str >= month_ago:
                                stats['thisMonth'] += 1
                            
                            # Add to recent activity (last 10)
                            if len(stats['recentActivity']) < 10:
                                stats['recentActivity'].append({
                                    'id': len(stats['recentActivity']) + 1,
                                    'user': f"User {row.get('User ID', 'Unknown')}",
                                    'time': dt.strftime("%I:%M %p"),
                                    'status': row.get('Status', 'Check-in')
                                })
                        except ValueError:
                            continue
        
        return jsonify(stats)
        
    except Exception as e:
        return jsonify({'error': f'Error getting stats: {str(e)}'}), 500

@app.route('/test/model', methods=['GET'])
def test_model():
    """Test if the face recognition model is working and check alignment"""
    try:
        model_file = "face_recognizer.yml"
        if not os.path.exists(model_file):
            return jsonify({'error': 'Model file not found'}), 400
        
        recognizer = cv2.face.LBPHFaceRecognizer_create()
        recognizer.read(model_file)
        
        # Check registered faces in folders
        face_dir = "registered_faces"
        folder_users = []
        if os.path.exists(face_dir):
            folder_users = [d for d in os.listdir(face_dir) if os.path.isdir(os.path.join(face_dir, d))]
        
        # Check users in JSON data
        json_users = []
        user_data_file = "user_data.json"
        if os.path.exists(user_data_file):
            with open(user_data_file, 'r') as f:
                user_data = json.load(f)
                json_users = list(user_data.keys())
        
        return jsonify({
            'model_exists': True,
            'model_file_size': os.path.getsize(model_file),
            'folder_users': folder_users,
            'json_users': json_users,
            'alignment_issue': len(folder_users) != len(json_users),
            'confidence_threshold': 150,
            'status': 'Model is ready for recognition'
        })
    except Exception as e:
        return jsonify({'error': f'Model test failed: {str(e)}'}), 500

@app.route('/attendance/data', methods=['GET'])
def get_attendance_data():
    """Get detailed attendance data for reports"""
    try:
        import datetime
        import csv
        
        attendance_data = []
        
        # Read attendance log if it exists
        log_file = "attendance_log.csv"
        if os.path.exists(log_file):
            with open(log_file, 'r', newline='') as file:
                reader = csv.DictReader(file)
                for row in reader:
                    timestamp = row.get('Timestamp', '')
                    user_id = row.get('User ID', 'Unknown')
                    name = row.get('User Name', 'Unknown')
                    status = row.get('Status', 'Check-in')
                    
                    if timestamp:
                        try:
                            # Parse timestamp
                            dt = datetime.datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
                            
                            # Create attendance record
                            attendance_data.append({
                                'date': dt.strftime("%Y-%m-%d"),
                                'user': f"User {user_id}",
                                'checkin': dt.strftime("%I:%M %p"),
                                'checkout': dt.strftime("%I:%M %p"),  # Same time for now
                                'duration': '8h 0m',  # Default duration
                                'status': status,
                                "name": name
                            })
                        except ValueError:
                            continue
        
        return jsonify({'attendance': attendance_data})
        
    except Exception as e:
        return jsonify({'error': f'Error getting attendance data: {str(e)}'}), 500

@app.route('/debug/recognize', methods=['POST'])
def debug_recognition():
    """Debug endpoint to test recognition with detailed output"""
    data = request.get_json()
    image_data = data.get('image')
    
    if not image_data:
        return jsonify({'error': 'Image data is required'}), 400
    
    try:
        # Decode the base64 image
        header, encoded = image_data.split(',', 1)
        image_bytes = base64.b64decode(encoded)
        
        # Convert to numpy array
        nparr = np.frombuffer(image_bytes, np.uint8)
        img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        
        if img is None:
            return jsonify({'error': 'Invalid image data'}), 400
        
        # Convert to grayscale
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        
        # Load face cascade
        face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
        
        # Detect faces with different parameters
        faces_1 = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=4, minSize=(30, 30))
        faces_2 = face_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=6, minSize=(50, 50))
        
        debug_info = {
            'image_size': f"{img.shape[1]}x{img.shape[0]}",
            'faces_detected_sensitive': len(faces_1),
            'faces_detected_normal': len(faces_2),
            'face_locations_sensitive': faces_1.tolist() if len(faces_1) > 0 else [],
            'face_locations_normal': faces_2.tolist() if len(faces_2) > 0 else []
        }
        
        if len(faces_1) == 0:
            return jsonify({
                'success': False,
                'message': 'No face detected with sensitive parameters',
                'debug_info': debug_info
            }), 400
        
        # Get the first detected face
        (x, y, w, h) = faces_1[0]
        face_img = gray[y:y + h, x:x + w]
        face_img = preprocess_face(face_img)
        
        # Load and use the recognizer
        try:
            recognizer = cv2.face.LBPHFaceRecognizer_create()
            model_file = "face_recognizer.yml"
            
            if not os.path.exists(model_file):
                return jsonify({'error': 'Model file not found. Train the model first.'}), 400
            
            recognizer.read(model_file)
            user_id, confidence = recognizer.predict(face_img)
            
            # Test different thresholds
            thresholds = [80, 85, 90, 95, 100]
            threshold_results = {}
            
            for threshold in thresholds:
                threshold_results[f'threshold_{threshold}'] = {
                    'recognized': confidence < threshold,
                    'confidence': round(confidence, 2)
                }
            
            debug_info.update({
                'recognition_results': {
                    'user_id': int(user_id),
                    'confidence': round(confidence, 2),
                    'threshold_tests': threshold_results
                }
            })
            
            return jsonify({
                'success': True,
                'user_id': int(user_id),
                'confidence': round(confidence, 2),
                'debug_info': debug_info,
                'message': f'Debug recognition completed'
            })
                
        except Exception as e:
            return jsonify({'error': f'Recognition error: {str(e)}'}), 500
            
    except Exception as e:
        return jsonify({'error': f'Image processing error: {str(e)}'}), 500

# InsightFace API Endpoints
@app.route('/insightface/embeddings', methods=['GET'])
def get_insightface_embeddings():
    """Get all InsightFace embeddings for standalone app"""
    if not INSIGHTFACE_AVAILABLE:
        return jsonify({
            'success': False,
            'error': 'InsightFace not available'
        }), 503
    
    try:
        all_embeddings = []
        all_names = []
        all_ids = []
        
        # Load all embedding files
        embedding_files = [f for f in os.listdir('.') if f.startswith('insightface_embeddings_') and f.endswith('.pkl')]
        
        print(f"🔄 Loading {len(embedding_files)} InsightFace embedding files...")
        
        for embedding_file in embedding_files:
            try:
                with open(embedding_file, 'rb') as f:
                    data = pickle.load(f)
                    user_id = data['user_id']
                    
                    # Get user info from user_data.json
                    if os.path.exists('user_data.json'):
                        with open('user_data.json', 'r') as f:
                            user_data = json.load(f)
                            user_info = user_data.get(user_id, {})
                            user_name = user_info.get('name', f'User {user_id}')
                    else:
                        user_name = f'User {user_id}'
                    
                    # Add embeddings for this user
                    for embedding in data['embeddings']:
                        all_embeddings.append(embedding.tolist())
                        all_names.append(user_name)
                        all_ids.append(user_id)
                        
                print(f"✅ Loaded embeddings for {user_name} (ID: {user_id})")
                        
            except Exception as e:
                print(f"⚠️ Error loading {embedding_file}: {e}")
                continue
        
        print(f"✅ Total embeddings loaded: {len(all_embeddings)}")
        
        return jsonify({
            'success': True,
            'embeddings': all_embeddings,
            'names': all_names,
            'ids': all_ids,
            'count': len(all_embeddings)
        })
        
    except Exception as e:
        print(f"❌ Error in get_insightface_embeddings: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500

@app.route('/insightface/recognize', methods=['POST'])
def insightface_recognize():
    """Recognize face using InsightFace"""
    if not INSIGHTFACE_AVAILABLE:
        return jsonify({
            'success': False,
            'error': 'InsightFace not available'
        }), 503
    
    try:
        data = request.get_json()
        image_data = data.get('image')
        
        if not image_data:
            return jsonify({'error': 'No image data provided'}), 400
        
        # Decode image
        header, encoded = image_data.split(',', 1)
        image_bytes = base64.b64decode(encoded)
        nparr = np.frombuffer(image_bytes, np.uint8)
        img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        
        if img is None:
            return jsonify({
                'success': False,
                'error': 'Invalid image data'
            }), 400
        
        # Initialize InsightFace if not already done
        if not initialize_insightface():
            return jsonify({
                'success': False,
                'error': 'Failed to initialize InsightFace model'
            }), 500
        
        # Get face embedding with more sensitive detection
        print(f"🔍 Processing image: {img.shape}")
        faces = insightface_model.get(img, max_num=1)
        print(f"🔍 Faces detected: {len(faces) if faces else 0}")
        
        if not faces:
            # Try OpenCV face detection as fallback
            print("🔄 InsightFace failed, trying OpenCV face detection...")
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
            opencv_faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(30, 30))
            print(f"🔍 OpenCV faces detected: {len(opencv_faces)}")
            
            if len(opencv_faces) == 0:
                return jsonify({
                    'success': False,
                    'error': 'No face detected',
                    'message': 'Please ensure your face is clearly visible in the camera',
                    'fallback': 'Try adjusting lighting or camera angle',
                    'debug_info': {
                        'image_shape': img.shape,
                        'image_channels': img.shape[2] if len(img.shape) > 2 else 1,
                        'insightface_detection': 'failed',
                        'opencv_detection': 'failed'
                    }
                }), 400
            else:
                return jsonify({
                    'success': False,
                    'error': 'Face detected but InsightFace processing failed',
                    'message': 'Face found but unable to process with InsightFace',
                    'fallback': 'Try using OpenCV recognition instead',
                    'debug_info': {
                        'image_shape': img.shape,
                        'opencv_faces_found': len(opencv_faces),
                        'insightface_detection': 'failed',
                        'opencv_detection': 'success'
                    }
                }), 400
        
        face_embedding = faces[0].embedding
        
        # Compare with known embeddings
        best_match = None
        best_similarity = 0.0
        
        # Load settings to get threshold
        settings = load_settings()
        threshold = float(settings.get('insightface_threshold', 0.6))  # Cosine similarity threshold (higher is better)
        print(f"🔍 Using InsightFace threshold: {threshold}")
        
        # Load all embeddings
        embedding_files = [f for f in os.listdir('.') if f.startswith('insightface_embeddings_') and f.endswith('.pkl')]
        
        for embedding_file in embedding_files:
            try:
                with open(embedding_file, 'rb') as f:
                    data = pickle.load(f)
                    user_id = data['user_id']
                    
                    for known_embedding in data['embeddings']:
                        # Calculate cosine similarity (higher is better)
                        similarity = float(np.dot(face_embedding, known_embedding) / (np.linalg.norm(face_embedding) * np.linalg.norm(known_embedding)))
                        print(f"🔍 User {user_id} similarity: {similarity:.3f} (threshold: {threshold})")
                        
                        if similarity > best_similarity and similarity > threshold:
                            best_similarity = float(similarity)  # Convert numpy.float32 to Python float
                            best_match = user_id
                            print(f"✅ New best match: User {user_id} with similarity {similarity:.3f}")
                            
            except Exception as e:
                print(f"⚠️ Error loading {embedding_file}: {e}")
                continue
        
        if best_match:
            confidence = float(best_similarity)  # Convert numpy.float32 to Python float
            
            # Fetch employee information from live API endpoint
            print(f"✅ RECOGNITION SUCCESS: User {best_match} recognized with similarity {confidence}")
            print(f"🔄 Fetching employee information for User {best_match} from live API...")
            employee_info = fetch_employee_info(best_match)
            print(f"📋 Employee info result: {employee_info}")

            # Log attendance
            import datetime
            import csv

            now = datetime.datetime.now()
            timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
            today = now.strftime("%Y-%m-%d")

            log_file = "attendance_log.csv"

            if not os.path.exists(log_file) or os.stat(log_file).st_size == 0:
                with open(log_file, "w", newline="") as file:
                    writer = csv.writer(file)
                    writer.writerow(["Timestamp", "User ID", "User Name", "Status"])

            attendance_status = "Check-in"
            message = f'User {employee_info["name"]} (ID: {best_match}) checked in successfully'

            all_records = []
            today_records = []

            with open(log_file, 'r', newline='') as file:
                reader = csv.DictReader(file)
                for row in reader:
                    all_records.append(row)
                    if row.get('User ID') == str(best_match) and row.get('Timestamp', '').startswith(today):
                        today_records.append(row)

            check_in_exists = any(r.get('Status') == 'Check-in' for r in today_records)
            check_out_exists = any(r.get('Status') == 'Check-out' for r in today_records)

            if not check_in_exists:
                attendance_status = "Check-in"
                message = f'User {employee_info["name"]} (ID: {best_match}) checked in successfully'
                all_records.append({'Timestamp': timestamp, 'User ID': str(best_match), 'User Name': employee_info["name"], 'Status': attendance_status})
            elif check_in_exists and not check_out_exists:
                attendance_status = "Check-out"
                message = f'User {employee_info["name"]} (ID: {best_match}) checked out successfully'
                all_records.append({'Timestamp': timestamp, 'User ID': str(best_match), 'User Name': employee_info["name"], 'Status': attendance_status})
            elif check_in_exists and check_out_exists:
                attendance_status = "Check-out"
                message = f'User {employee_info["name"]} (ID: {best_match}) checkout time updated'
                for i in reversed(range(len(all_records))):
                    record = all_records[i]
                    if record.get('User ID') == str(best_match) and record.get('Timestamp', '').startswith(today) and record.get('Status') == 'Check-out':
                        record['Timestamp'] = timestamp
                        record['User Name'] = employee_info["name"]
                        break
                else:
                    all_records.append({'Timestamp': timestamp, 'User ID': str(best_match), 'User Name': employee_info["name"], 'Status': attendance_status})

            with open(log_file, "w", newline="") as file:
                writer = csv.DictWriter(file, fieldnames=["Timestamp", "User ID", "User Name", "Status"])
                writer.writeheader()
                writer.writerows(all_records)
            
            return jsonify({
                'success': True,
                'user_id': best_match,
                'user_name': employee_info["name"],
                'user_email': employee_info["email"],
                'user_department': employee_info["department"],
                'user_status': employee_info["status"],
                'confidence': round(confidence, 3),
                'timestamp': timestamp,
                'attendance_status': attendance_status,
                'message': message,
                'method': 'insightface',
                'similarity': round(float(best_similarity), 3)
            })
        else:
            # Enhanced error response with fallback information
            return jsonify({
                'success': False,
                'error': 'No match found',
                'threshold': float(threshold),
                'message': 'Face detected but no matching user found in database',
                'fallback': 'Try registering the user or check if embeddings exist'
            }), 400
            
    except Exception as e:
        print(f"❌ Error in insightface_recognize: {e}")
        # Fallback to OpenCV recognition if InsightFace fails
        try:
            print("🔄 Attempting fallback to OpenCV recognition...")
            # Call the regular OpenCV recognition endpoint
            from flask import current_app
            with current_app.test_request_context('/recognize', method='POST', json={'image': data.get('image')}):
                opencv_result = recognize_face()
                if hasattr(opencv_result, 'get_json'):
                    opencv_data = opencv_result.get_json()
                    if opencv_data.get('success'):
                        opencv_data['method'] = 'opencv_fallback'
                        opencv_data['fallback_reason'] = f'InsightFace failed: {str(e)}'
                        return jsonify(opencv_data)
        except Exception as fallback_error:
            print(f"❌ Fallback to OpenCV also failed: {fallback_error}")
        
        return jsonify({
            'success': False,
            'error': str(e),
            'fallback_attempted': True,
            'message': 'Both InsightFace and OpenCV recognition failed'
        }), 500

if __name__ == '__main__':
    app.run(debug=True, port=5001)
