import os

# ==========================================
# 0. CRITICAL CPANEL CONFIGURATION
# ==========================================
# These lines force TensorFlow to use only 1 thread.
# This prevents the "pthread_create failed" error on shared hosting.
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
os.environ['OMP_NUM_THREADS'] = '1' 
os.environ['TF_NUM_INTRAOP_THREADS'] = '1'
os.environ['TF_NUM_INTEROP_THREADS'] = '1'

import pickle
import numpy as np
# TensorFlow must be imported AFTER setting the variables above
import tensorflow as tf 

from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input
from tensorflow.keras.preprocessing import image
from sklearn.metrics.pairwise import cosine_similarity

# ==========================================
# 1. GLOBAL VARIABLES (Lazy Loading)
# ==========================================
_model = None
_database = None

def get_model():
    """Lazy loads the AI model only when needed to save RAM."""
    global _model
    if _model is None:
        # Configure TensorFlow strictly for single-threading before loading model
        tf.config.threading.set_intra_op_parallelism_threads(1)
        tf.config.threading.set_inter_op_parallelism_threads(1)
        
        print("Loading AI Model... (This happens only once)")
        _model = MobileNetV2(weights='imagenet', include_top=False, pooling='avg')
        print("AI Model Loaded Successfully!")
    return _model

def get_database():
    """Lazy loads the product database only when needed."""
    global _database
    if _database is None:
        pkl_path = os.path.join(os.path.dirname(__file__), 'product_embeddings.pkl')
        try:
            with open(pkl_path, 'rb') as f:
                _database = pickle.load(f)
            print(f"Database loaded: {len(_database)} products ready.")
        except FileNotFoundError:
            print("ERROR: product_embeddings.pkl not found!")
            _database = []
    return _database

# ==========================================
# 2. HELPER: PROCESS IMAGE
# ==========================================
def process_uploaded_image(img_file):
    """
    Takes the uploaded file, saves it temporarily, converts it to numbers, then deletes it.
    """
    temp_filename = 'temp_search_image.jpg'
    
    # Save temp file
    with open(temp_filename, 'wb+') as destination:
        for chunk in img_file.chunks():
            destination.write(chunk)

    try:
        # Load and resize image to 224x224 (required by MobileNetV2)
        img = image.load_img(temp_filename, target_size=(224, 224))
        x = image.img_to_array(img)
        x = np.expand_dims(x, axis=0)
        x = preprocess_input(x)

        # Get the model safely
        model = get_model()

        # Extract features (numbers)
        features = model.predict(x, verbose=0).flatten()
        return features

    except Exception as e:
        print(f"Error processing image: {e}")
        return None
    finally:
        # Clean up temp file
        if os.path.exists(temp_filename):
            os.remove(temp_filename)

# ==========================================
# 3. VIEWS
# ==========================================

# VIEW 1: The Frontend Page
def index(request):
    """Renders the HTML interface"""
    return render(request, 'index.html')

# VIEW 2: The Search API
@csrf_exempt
def search_product(request):
    if request.method == 'POST':
        try:
            if 'image' not in request.FILES:
                return JsonResponse({'status': 'error', 'message': 'No image found. Use key "image".'})

            uploaded_file = request.FILES['image']
            
            # Step A: Convert upload to numbers
            query_features = process_uploaded_image(uploaded_file)
            
            if query_features is None:
                return JsonResponse({'status': 'error', 'message': 'Could not process image - Server Memory Limit?'})

            # Step B: Load Database & Compare
            database = get_database()
            
            if not database:
                 return JsonResponse({'status': 'error', 'message': 'Database is empty or missing.'})

            db_features = np.array([item['features'] for item in database])
            similarities = cosine_similarity([query_features], db_features)[0]

            # Step C: Get Top Matches
            top_indices = similarities.argsort()[::-1][:10]
            results = []
            seen_ids = set()

            for idx in top_indices:
                score = float(similarities[idx])
                item = database[idx]
                p_id = item['product_id']
                
                # --- NEW LOGIC: Get the Real Filename ---
                # This fetches the filename you saved in the new pickle file (e.g., 'image_a1b46b.jpg')
                # It falls back to f"{p_id}.jpg" only if the new pickle hasn't been uploaded yet.
                real_filename = item.get('image_filename', f"{p_id}.jpg")

                # Filter: Score > 40% and Unique ID
                if score > 0.4 and p_id not in seen_ids:
                    
                    # 1. Product Page Link
                    product_link = f"https://ladonna.com.bd/product/product_description.php?id={p_id}"
                    
                    # 2. Image Link (Using real_filename)
                    # NOTE: I used 'uploads' because your zip file was named 'uploads.zip'.
                    # If the images are in 'product_images' on the server, change 'uploads' to 'product_images'.
                    image_link = f"https://ladonna.com.bd/uploads/{real_filename}"
                    
                    results.append({
                        'product_id': p_id,
                        'score': f"{round(score * 100, 1)}%",
                        'product_path': product_link,
                        'image_url': image_link
                    })
                    seen_ids.add(p_id)
                
                if len(results) >= 5:
                    break
            
            return JsonResponse({'status': 'success', 'matches': results})

        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})

    return JsonResponse({'status': 'error', 'message': 'Only POST requests allowed.'})