from django.shortcuts import render, redirect
from .models import Feedback
from .models import FaceProfile
from django.core.files.base import ContentFile
import base64

#mport face_recognition
from django.http import JsonResponse
from .utils import decode_base64_image
import numpy as np
import face_recognition
from django.core.files.base import ContentFile
import uuid
import io
import openai
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
import json, logging, re
import os
import difflib
import traceback
from .models import PredefinedQA
from django.utils.safestring import mark_safe
from .models import ChatLog,ChatCategory
from django.views.decorators.clickjacking import xframe_options_exempt
from sentence_transformers import SentenceTransformer, util
from .utils import generate_ai_response, get_or_create_session_data, handle_category_selection, identify_contact, find_best_match_qa, save_conversation

logger = logging.getLogger(__name__)
def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        return x_forwarded_for.split(',')[0].strip()
    return request.META.get('REMOTE_ADDR')

@xframe_options_exempt
def feedback_widget(request):
    ip = get_client_ip(request)
    already_submitted = Feedback.objects.filter(ip_address=ip).exists()
    show_thank_you = False
    redirect_to_google = False

    if request.method == 'POST':
        try:
            rating = int(request.POST.get('rating'))
            comment = request.POST.get('comment', '')
            contact = request.POST.get('contact', '')
            referrer = request.META.get('HTTP_REFERER', '')

            Feedback.objects.create(
                rating=rating,
                comment=comment,
                contact=contact,
                ip_address=ip,
                referrer=referrer
            )

            # Set flag for redirect if rating >= 4
            if rating >= 4:
                redirect_to_google = True

            # Redirect after POST to avoid resubmission
            return redirect(f"{request.path}?submitted=1&google={1 if redirect_to_google else 0}")

        except Exception as e:
            print("[ERROR] Feedback submission failed:", e)

    # Show Thank You message and Google Redirect based on GET params
    if request.GET.get('submitted') == '1':
        show_thank_you = True
    if request.GET.get('google') == '1':
        redirect_to_google = True

    return render(request, 'feedback/feedback_form.html', {
        'already_submitted': already_submitted,
        'show_thank_you': show_thank_you,
        'redirect_to_google': redirect_to_google,
    })

def face_register(request):
    if request.method == "POST":
        name = request.POST.get("name", "").strip()
        phone = request.POST.get("phone", "").strip()
        image_data = request.POST.get("image_data")

        if not name or not phone:
            return JsonResponse({
                "success": False,
                "message": "Name and phone number are required."
            })

        if not image_data:
            return JsonResponse({
                "success": False,
                "message": "Image data is missing."
            })

        image = decode_base64_image(image_data)
        if image is None:
            return JsonResponse({
                "success": False,
                "message": "Invalid image data."
            })

        image_np = np.array(image)
        face_locations = face_recognition.face_locations(image_np)
        if not face_locations:
            return JsonResponse({
                "success": False,
                "message": "No face found in image."
            })

        face_encodings = face_recognition.face_encodings(image_np, face_locations)
        encoding = face_encodings[0]

        for profile in FaceProfile.objects.all():
            known_encoding = profile.get_encoding()
            if known_encoding is not None:
                matches = face_recognition.compare_faces([known_encoding], encoding, tolerance=0.5)
                if matches[0]:
                    return JsonResponse({
                        "success": False,
                        "message": "This face is already registered."
                    })

        file_name = f"{uuid.uuid4().hex}.jpg"
        image_io = io.BytesIO()
        image.save(image_io, format='JPEG')
        image_file = ContentFile(image_io.getvalue(), name=file_name)

        profile = FaceProfile(name=name, phone_number=phone, face_image=image_file)
        profile.set_encoding(encoding)
        profile.save()

        return JsonResponse({
            "success": True,
            "message": "Face registered successfully!"
        })

    return JsonResponse({
        "success": False,
        "message": "Invalid request method."
    })

def face_login(request):
    if request.method == "POST":
        image_data = request.POST.get("image_data")
        image = decode_base64_image(image_data)

        if image is None:
            return JsonResponse({"success": False, "message": "Invalid image data."})

        image_np = np.array(image)
        face_locations = face_recognition.face_locations(image_np)
        if not face_locations:
            return JsonResponse({"success": False, "message": "No face detected."})

        face_encodings = face_recognition.face_encodings(image_np, face_locations)
        login_encoding = face_encodings[0]

        for profile in FaceProfile.objects.all():
            known_encoding = profile.get_encoding()
            if known_encoding is not None:
                matches = face_recognition.compare_faces([known_encoding], login_encoding, tolerance=0.5)
                if matches[0]:
                    request.session['phone_number'] = profile.phone_number
                    return JsonResponse({
                        "success": True,
                        "message": f"Welcome, {profile.name}!",
                        "phone": profile.phone_number
                    })


        return JsonResponse({"success": False, "message": "Face not recognized."})

    return render(request, "feedback/face_login.html")



@csrf_exempt
@xframe_options_exempt
def chat_widget(request):
    return render(request, "feedback/chat_widget.html")

@csrf_exempt
@xframe_options_exempt
# Chat API function
@csrf_exempt
def chat_api(request):
    if request.method != "POST":
        return JsonResponse({"answer": "Invalid request."})

    try:
        data = json.loads(request.body)
        message = data.get("message", "").strip()
        session_id = data.get("session_id")
        user_name = data.get("name", "").strip()
        user_contact = data.get("contact", "").strip()

        if not message or not session_id:
            return JsonResponse({"answer": "Message and session_id are required."})

        session_key = f"chat_user_{session_id}"
        session_data = get_or_create_session_data(request.session, session_key, user_name, user_contact)

        # Check if the message is for resetting the category
        if message.lower() in ["restart", "clear", "start over"]:
            session_data.pop("category_id", None)
            request.session[session_key] = session_data
            return JsonResponse({
                "answer": "Category selection has been reset. Please choose a main category to continue:",
                "categories": [cat.name for cat in ChatCategory.objects.filter(parent__isnull=True, is_active=True)]
            })

        # Step 1: Ask for name
        if "name" not in session_data:
            return JsonResponse({"answer": "Hey there! May I know your name so I can assist you better?"})

        # Step 2: Ask for contact
        if "contact" not in session_data:
            return JsonResponse({
                "answer": f"Nice to meet you, {session_data['name']}! Could you please share your email or phone number?"
            })

        # Step 3: Handle category tree
        current_cat_id = session_data.get("category_id")
        current_category = ChatCategory.objects.filter(id=current_cat_id).first() if current_cat_id else None
        subcategories = ChatCategory.objects.filter(parent=current_category, is_active=True)

        if subcategories.exists():
            sub_names = [cat.name.lower() for cat in subcategories]

            if message.lower() in sub_names:
                selected = subcategories.get(name__iexact=message)
                session_data["category_id"] = selected.id
                request.session[session_key] = session_data

                child_subs = ChatCategory.objects.filter(parent=selected, is_active=True)
                if child_subs.exists():
                    return JsonResponse({
                        "answer": f"You selected: {selected.name}. Please choose a subcategory:",
                        "categories": [cat.name for cat in child_subs]
                    })
                else:
                    return JsonResponse({
                        "answer": f"You selected the final category: {selected.name}. Now, please ask your question."
                    })

            # User hasn't selected a valid subcategory yet
            return JsonResponse({
                "answer": "Please choose a category from the following:",
                "categories": [cat.name for cat in subcategories]
            })

        # Step 4: No more subcategories, answer the question
        if current_category:
            user_email, user_phone = identify_contact(session_data["contact"])
            best_matches = find_best_match_qa(message, current_category) 

            if len(best_matches) > 1:
                options = [f"{i+1}. {qa.question}" for i, qa in enumerate(best_matches)]
                return JsonResponse({
                    "answer": "Your question matched multiple entries. Please choose one of the following:",
                    "options": options
                })

            answer = best_matches[0].answer if best_matches else generate_ai_response(message, session_data)
            save_conversation(session_id, session_data, message, answer)

            return JsonResponse({"answer": answer})

        # Step 5: Show root categories (initial interaction)
        root_categories = ChatCategory.objects.filter(parent__isnull=True, is_active=True)
        root_names = [cat.name.lower() for cat in root_categories]

        if message.lower() in root_names:
            selected = root_categories.get(name__iexact=message)
            session_data["category_id"] = selected.id
            request.session[session_key] = session_data

            subs = ChatCategory.objects.filter(parent=selected, is_active=True)
            return JsonResponse({
                "answer": f"You selected: {selected.name}. Please choose a subcategory:",
                "categories": [cat.name for cat in subs]
            })

        return JsonResponse({
            "answer": (
                f"Thank you, {session_data['name']}! You're connected to SkyBee Assistant. "
                "Please select one of the following main categories to continue:"
            ),
            "categories": [cat.name for cat in root_categories]
        })

    except Exception as e:
        logger.exception("Error in chat_api:")
        return JsonResponse({"answer": "An error occurred. Please try again."})


# Reset Category API function
@csrf_exempt
def reset_category(request):
    try:
        data = json.loads(request.body)
        session_id = data.get("session_id")

        if not session_id:
            return JsonResponse({"answer": "Session ID is required."})

        session_key = f"chat_user_{session_id}"
        session_data = request.session.get(session_key, {})

        # Check if user name and contact info exist in the session
        user_name = session_data.get("user_name")
        user_contact = session_data.get("user_contact")

        # Reset the category_id (this removes the selected category)
        session_data.pop("category_id", None)
        request.session[session_key] = session_data

        # If name and contact are not in session, prompt the user for them
        if not user_name or not user_contact:
            return JsonResponse({
                "answer": "Please enter your name and contact info.",
                "prompt_for_details": True
            })

        # After resetting, prompt the user to select a category again
        root_categories = ChatCategory.objects.filter(parent__isnull=True, is_active=True)
        return JsonResponse({
            "answer": "Category selection has been cleared. Please choose a category to continue.",
            "categories": [cat.name for cat in root_categories]
        })

    except Exception as e:
        logger.exception("Error resetting category:")
        return JsonResponse({"answer": "Something went wrong while resetting the category."})



@csrf_exempt
def suggestions_api(request):
    q = request.GET.get('q', '').strip().lower()
    suggestions = []

    # Ensure session key exists for user
    session_id = request.GET.get("session_id")
    if not session_id:
        return JsonResponse({"suggestions": ["Missing session_id."]})

    session_key = f"chat_user_{session_id}"
    session_data = request.session.get(session_key, {})

    # Get selected category from session
    category_id = session_data.get("category_id")
    if not category_id:
        return JsonResponse({"suggestions": ["Please select a category first."]})

    try:
        current_category = ChatCategory.objects.get(id=category_id)

        # Only allow suggestions for final category (no children)
        has_children = ChatCategory.objects.filter(parent=current_category, is_active=True).exists()
        if has_children:
            return JsonResponse({"suggestions": ["Please select a final category to see suggestions."]})

        if q:
            matched_qas = PredefinedQA.objects.filter(
                category=current_category,
                question__icontains=q
            )[:10]
            suggestions = [qa.question for qa in matched_qas]

        if not suggestions:
            suggestions = ["No questions found for this category. Try a different keyword."]

    except ChatCategory.DoesNotExist:
        suggestions = ["Invalid category selected. Please restart."]

    return JsonResponse({"suggestions": suggestions})
