import os
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt

from langchain_community.document_loaders import PyPDFLoader, CSVLoader, UnstructuredExcelLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain_huggingface import HuggingFaceEmbeddings

from dotenv import load_dotenv

from user_panel.models import ChatBot, UserLeads, EndUser
from .models import Conversation

load_dotenv()

embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")

VECTORSTORES = {}
CONVERSATIONS = {}

GREETINGS = {
    "hi": "Hello! How can I help you today?",
    "hello": "Hi there! How are you doing?",
    "hey": "Hey! What can I do for you?",
    "how are you": "I’m just a bot, but I’m doing great! 😊",
    "bye": "Goodbye! Take care!",
    "thank you": "You're welcome!",
    "thanks": "Glad I could help!"
}

INTENTS = {
    "order": "LEAD_CAPTURE",
    "menu": "Would you like to see the menu?",
    "book": "LEAD_CAPTURE", 
    "booking": "LEAD_CAPTURE",
    "reservation": "LEAD_CAPTURE",
    "recommend": "Pasta and desserts are highly recommended!"
}


def save_lead_from_request(data, chatbot_id):
    """Save lead information to database"""
    try:
        chatbot = ChatBot.objects.filter(id=chatbot_id).first()
        if not chatbot:
            return {"error": "Chatbot not found."}
        
        user = chatbot.user
        
        lead = UserLeads.objects.create(
            name=data.get("name"),
            email=data.get("email"),
            phone_number=data.get("phone_number"),
            lead=data.get("lead", ""),
            note=data.get("note", ""),
            address=data.get("address", ""),
            type=data.get("type", "general"),
            status="new",
            chatbot=chatbot  # Add chatbot foreign key
        )
        
        return {"success": True, "message": "📝 Lead saved successfully! We'll contact you soon.", "lead_id": lead.id}
    except Exception as e:
        return {"error": f"Failed to save lead: {str(e)}"}


def get_next_lead_question(chat_history, inquiry_type):
    """Determine what information to ask for next in the lead capture flow"""
    # Extract collected information from chat history
    collected_info = {}
    for msg in chat_history:
        if msg.get("user"):
            user_msg = msg["user"].lower()
            bot_msg = msg.get("bot", "")
            
            # Check if user provided name
            if "what's your name" in bot_msg or "your name" in bot_msg:
                if len(user_msg.split()) >= 2:  # Assuming name has at least 2 words
                    collected_info["name"] = msg["user"]
            
            # Check if user provided email
            elif "email" in bot_msg and "@" in user_msg:
                collected_info["email"] = msg["user"]
            
            # Check if user provided phone
            elif "phone" in bot_msg and any(char.isdigit() for char in user_msg):
                collected_info["phone_number"] = msg["user"]
            
            # Check if user provided additional notes
            elif "special requirements" in bot_msg or "anything else" in bot_msg:
                collected_info["note"] = msg["user"]
    
    # Determine next question
    if not collected_info.get("name"):
        return f"Great! I'd be happy to help you with your {inquiry_type}. What's your full name?"
    elif not collected_info.get("email"):
        return f"Nice to meet you, {collected_info.get('name', 'there')}! What's your email address?"
    elif not collected_info.get("phone_number"):
        return "Perfect! What's your phone number?"
    elif not collected_info.get("note"):
        return f"Do you have any special requirements or notes for your {inquiry_type}?"
    else:
        return "LEAD_COMPLETE"  # All information collected


def save_lead_from_chat_history(chat_history, chatbot_id, inquiry_type):
    """Extract lead information from chat history and save it"""
    try:
        collected_info = {"type": inquiry_type}
        
        for msg in chat_history:
            if msg.get("user"):
                user_msg = msg["user"]
                bot_msg = msg.get("bot", "")
                
                # Extract name
                if "what's your name" in bot_msg or "your name" in bot_msg:
                    if len(user_msg.split()) >= 2:
                        collected_info["name"] = user_msg
                
                # Extract email
                elif "email" in bot_msg and "@" in user_msg:
                    collected_info["email"] = user_msg
                
                # Extract phone
                elif "phone" in bot_msg and any(char.isdigit() for char in user_msg):
                    collected_info["phone_number"] = user_msg
                
                # Extract notes
                elif "special requirements" in bot_msg or "anything else" in bot_msg:
                    collected_info["note"] = user_msg
        
        # Save the lead
        return save_lead_from_request(collected_info, chatbot_id)
    except Exception as e:
        return {"error": f"Failed to save lead: {str(e)}"}


def load_documents(user_id, chatbot_name):
    base_path = os.path.join("media", "data", str(user_id), chatbot_name)
    if not os.path.exists(base_path):
        return []

    documents = []
    for filename in os.listdir(base_path):
        full_path = os.path.join(base_path, filename)
        if filename.endswith(".pdf"):
            loader = PyPDFLoader(full_path)
        elif filename.endswith(".csv"):
            loader = CSVLoader(full_path)
        elif filename.endswith(".xlsx"):
            loader = UnstructuredExcelLoader(full_path)
        else:
            continue
        documents.extend(loader.load())
    return documents


def build_or_load_vectorstore(user_id, chatbot_name, load_existing=False):
    vectorstore_path = os.path.join("vectorstores", f"{user_id}_{chatbot_name}")
    os.makedirs("vectorstores", exist_ok=True)

    if load_existing and os.path.exists(vectorstore_path):
        return FAISS.load_local(vectorstore_path, embeddings, allow_dangerous_deserialization=True)

    docs = load_documents(user_id, chatbot_name)
    if not docs:
        return None

    splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
    split_docs = splitter.split_documents(docs)

    vectorstore = FAISS.from_documents(split_docs, embeddings)
    vectorstore.save_local(vectorstore_path)
    return vectorstore


def get_or_create_qa(user_id, chatbot_name, load_existing=False):
    key = f"{user_id}_{chatbot_name}"

    if key not in VECTORSTORES:
        vs = build_or_load_vectorstore(user_id, chatbot_name, load_existing)
        if not vs:
            return None, None
        VECTORSTORES[key] = vs
    else:
        vs = VECTORSTORES[key]

    retriever = vs.as_retriever(search_kwargs={"k": 5})
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)
    memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

    qa = ConversationalRetrievalChain.from_llm(llm, retriever=retriever, memory=memory)
    return qa, memory


# def save_lead_from_request(data):
#     required_fields = ["name", "email", "number", "inquiry_type"]
#     if not all(field in data for field in required_fields):
#         return {"error": "Missing one or more required lead fields."}

#     lead_data = {
#         "name": data["name"],
#         "email": data["email"],
#         "number": data["number"],
#         "inquiry_type": data["inquiry_type"],
#     }

#     os.makedirs("data", exist_ok=True)
#     lead_file = "data/leads.json"

#     if os.path.exists(lead_file):
#         with open(lead_file, "r") as f:
#             leads = json.load(f)
#     else:
#         leads = []

#     leads.append(lead_data)

#     with open(lead_file, "w") as f:
#         json.dump(leads, f, indent=4)

#     return {"success": True, "message": "📝 Lead saved successfully!"}





@csrf_exempt
def chat_with_bot(request, chatbot_id):
    if request.method != "POST":
        return JsonResponse({"error": "POST method required"}, status=400)

    try:
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON body."}, status=400)

        query = data.get("query", "").strip()
        load_existing = data.get("load_existing", True)

        chatbot = ChatBot.objects.filter(id=chatbot_id).first()
        if not chatbot:
            return JsonResponse({"error": "Chatbot not found for this user."}, status=404)

        user_id = chatbot.user.id  # Fixed: access user.id instead of user_id
        if not user_id or not query:
            return JsonResponse({"error": "Query is required in the request body."}, status=400)

        chatbot_name = chatbot.chatbot_name
        key = f"{user_id}_{chatbot_name}"

        global CONVERSATIONS

        if key not in CONVERSATIONS:
            qa, memory = get_or_create_qa(user_id, chatbot_name, load_existing)
            if not qa:
                return JsonResponse({"error": "No documents found for this chatbot."}, status=500)
            CONVERSATIONS[key] = {"qa": qa, "memory": memory, "chat_history": []}
        else:
            qa = CONVERSATIONS[key]["qa"]

        normalized_query = query.lower()

        if normalized_query in GREETINGS:
            response = GREETINGS[normalized_query]
        else:
            intent_match = next((v for k, v in INTENTS.items() if k in normalized_query), None)
            if intent_match:
                if intent_match == "LEAD_CAPTURE":
                    # Check if this is a lead submission with data
                    if data.get("name") and data.get("email") and data.get("phone_number"):
                        # This is a lead submission
                        lead_result = save_lead_from_request(data, chatbot_id)
                        if lead_result.get("success"):
                            response = lead_result["message"]
                        else:
                            response = f"❌ {lead_result.get('error', 'Failed to save lead')}"
                    else:
                        # This is an initial order/booking request - prompt for lead info step by step
                        inquiry_type = "order" if any(word in normalized_query for word in ["order", "food", "dish"]) else "booking"
                        response = (
                            f"Great! I'd be happy to help you with your {inquiry_type}. "
                            "Let me collect your information step by step.\n\n"
                            "**Step 1:** What's your full name?\n"
                            "(Please provide your name in the next message)"
                        )
                else:
                    response = intent_match
            else:
                response = qa.run(query)
                if response.lower() in ["i don't know", "i am not sure"]:
                    response = "⚠️ Sorry, I could not find that information in your documents."

        CONVERSATIONS[key]["chat_history"].append({"user": query, "bot": response})

        chat_history = CONVERSATIONS[key]["chat_history"]
        conversation_obj, created = Conversation.objects.get_or_create(
            user_id=user_id,
            domain=chatbot_name,
            defaults={"chat_history": chat_history}
        )
        if not created:
            conversation_obj.chat_history = chat_history
            conversation_obj.save()

        return JsonResponse({"response": response})

    except Exception as e:
        return JsonResponse({"error": f"Unexpected error: {str(e)}"}, status=500)
