from flask import Flask, request, jsonify, render_template, current_app, session
from session_manager import SessionManager
#from qdrant_client import QdrantClient
#from qdrant_client.http.models import VectorParams, Distance, PointStruct
#from qdrant_client.http.exceptions import UnexpectedResponse
import os
import requests
import re 
import uuid
from datetime import datetime
import time
import logging
import json
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_groq import ChatGroq
from config import Config
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage
from langchain.schema import Document  # Ensure this is imported
from langchain_core.prompts import PromptTemplate
#from langchain_community.vectorstores import Qdrant
from langchain_community.vectorstores import FAISS
from langchain.chains import LLMChain
from langchain.schema import BaseRetriever
from pydantic import PrivateAttr
from langchain.chains import RetrievalQA
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from chatbot import hotelgraph
from vector_store import VectorStore
from langchain_core.messages import AIMessage, HumanMessage
"""from" whatsapp.utils.whatsapp_utils import (
    process_whatsapp_message_forAgents,
    is_valid_whatsapp_message,
)
from whatsapp.decorators.security import signature_required"""


app = Flask(__name__)
app.config.from_object(Config)
app.secret_key = os.urandom(24)  # For session management

"""
qdrant_client = QdrantClient(
    url=app.config['QDRANT_URL'],
    api_key=app.config['QDRANT_API_KEY'],
)
"""

# Initialize the session manager with the hotelgraph client
session_manager = SessionManager(session_expiry_minutes=30,  llm_client=hotelgraph)

#kbvector_store = KBVectorStore()

#for Whatsapp cloud api to post
#GET METHOD 
"""@app.route('/webhook', methods=['GET'])
def whatsapp_webhook_get():
    return verify()
"""

# Required webhook verifictaion for WhatsApp
def verify():
    # Parse params from the webhook verification request
    print("FROM WHATSAPP..VERIFYING...")
    mode = request.args.get("hub.mode")
    token = request.args.get("hub.verify_token")
    challenge = request.args.get("hub.challenge")
    # Check if a token and mode were sent
    if mode and token:
        # Check the mode and token sent are correct
        if mode == "subscribe" and token == app.config['VERIFY_TOKEN']:
            # Respond with 200 OK and challenge token from the request
            logging.info("WEBHOOK_VERIFIED")
            return challenge, 200
        else:
            # Responds with '403 Forbidden' if verify tokens do not match
            logging.info("VERIFICATION_FAILED")
            return jsonify({"status": "error", "message": "Verification failed"}), 403
    else:
        # Responds with '400 Bad Request' if verify tokens do not match
        logging.info("MISSING_PARAMETER")
        return jsonify({"status": "error", "message": "Missing parameters"}), 400


#POST METHOD
"""@app.route('/webhook', methods=['POST'])
@signature_required
def whatsapp_webhook_post():
    return handle_incoming_whatsapp_msg()
"""

def handle_incoming_whatsapp_msg():
    """
    Handle incoming webhook events from the WhatsApp API.

    This function processes incoming WhatsApp messages and other events,
    such as delivery statuses. If the event is a valid message, it gets
    processed. If the incoming payload is not a recognized WhatsApp event,
    an error is returned.

    Every message send will trigger 4 HTTP requests to your webhook: message, sent, delivered, read.

    Returns:
        response: A tuple containing a JSON response and an HTTP status code.
    """

    body = request.get_json()
    # logging.info(f"request body: {body}")

    # Check if it's a WhatsApp status update
    if (
        body.get("entry", [{}])[0]
        .get("changes", [{}])[0]
        .get("value", {})
        .get("statuses")
    ):
        logging.info("Received a WhatsAp                                                                                                                                           [p status update.")
        return jsonify({"status": "ok"}), 200

    try:
        if is_valid_whatsapp_message(body):
            process_whatsapp_message_forAgents(body)
            return jsonify({"status": "ok"}), 200
        else:
            # if the request is not a WhatsApp API event, return an error
            return (
                jsonify({"status": "error", "message": "Not a WhatsApp API event"}),)
            404
    except json.JSONDecodeError:
        logging.error("Failed to decode JSON")
        return jsonify({"status": "error", "message": "Invalid JSON provided"}), 400
"""
os.environ['groq_api_key'] = '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'
groq_api_key = os.environ['groq_api_key']
#llm = ChatGroq(groq_api_key=groq_api_key, model_name='llama-3.1-70b-versatile',temperature=0)
llm = ChatGroq(groq_api_key=groq_api_key, model_name='llama-3.3-70b-versatile',temperature=0)
    """

@app.route('/')
def index():
    return render_template('index.html')


@app.route('/upload', methods=['POST'])
def upload_document():
    print(f"Creating FAISS store....")
    try:
        vector_store = VectorStore()
        print(f"vectorStore job done.")
        return "<div class='alert alert-success'>Knowledebase processed successfully</div>"
    except Exception as e:
        print(f"Error during query processing FAISS: {e}")
        return jsonify({"error": "An error occurred during query processing FAISS"}), 500
    finally:
        pass
        #os.remove(file_path)
        #print(f'File removed from {file_path}')


SYSTEM_TEMPLATE = """
You are Rumi, a friendly and efficient virtual assistant designed to enhance the guest experience at our hotel called Hotel International. 
Your job is to assists guests with a variety of needs, from booking and reservations to answering questions about hotel
amenities and local attractions.
You will answer questions based on the context provided only. Dont make up an answer.
However, if you cannot confidently answer a query:
Acknowledge that you cannot help directly, Inform the guest that you will log their request with the reception team,
Use the tool_catchall function to log the unresolved query. 

Important Guidelines:
- Always strive to provide the most helpful response possible
- If you do not find a satisfactory answer in the knowledge base:
    - Do not fabricate information
    - Do not guess or provide potentially incorrect information
    - Instead, use the catch-all tool to log the query for reception follow-up

Example Responses for Unresolved Queries:
"I apologize, but I don't have specific information about that. I'll log this request with our reception team, and they will get back to you shortly."
"I'm unable to help with this specific query at the moment. Our reception team will review your request and provide assistance."

Just stick with the context provided. Dont make up an answer. There are examples for you to follow. 
Just use them for your reference. DOnt use them as is when answering.
Always ask guest name and room no  when you greet.
Your Personality Traits:
Friendly and Welcoming: Always greets guests warmly and makes them feel valued.
Efficient and Knowledgeable: Provides quick and accurate information.
Patient and Attentive: Listens carefully to guest inquiries and provides thoughtful responses.
Professional and Polite: Maintains a high standard of professionalism and politeness at all times.
Show empathy when unable to resolve a query
Helpful and Resourceful: Goes the extra mile to assist guests with their needs and find solutions to their problems.
Your Interaction Style:
Greeting: Start with a warm and friendly greeting.
Example: “Hello and welcome to Hotel International! How can I assist you today? May I have your name and room no.”
Assisting with Inquiries:
Be clear and concise in providing information.
Example: “Our fitness center is open 24/7 and is located on the second floor, right next to the spa.”
Handling Requests:
Confirm understanding of the request.
Example: “I understand you would like extra towels sent to your room. I wll arrange that right away.”
Problem-Solving:
Acknowledge the issue and reassure the guest.
Example: “I am sorry to hear you are experiencing this issue. Let me take care of that for you immediately.”
Local Recommendations:
Provide personalized suggestions.s
Example: “If you re looking for a great place to dine, I recommend The Bistro, which is just a 
5-minute walk from the hotel?”

Your Key Functions:
Reservation Management:
Assist with booking rooms, modifying reservations, and checking availability.
Information Provider:
Provide details about hotel amenities, services, and policies.
Example: pool hours, Wi-Fi password, dining options.
Concierge Services:
Recommend local attractions, dining options, and transportation services.
Example: arrange taxis, suggest sightseeing tours.
Room Service Requests:
Handle guest requests for additional amenities, housekeeping, and room service.
YOur eedback Collection:
Gather guest feedback to improve services.
Example: “How was your stay with us? We would love to hear your feedback!”

Example Dialogue for your reference:
Guest: “Hi, I need to know the check-out time, please.” Rumi: “Greetings! Our check-out time is 11 AM. If you need a late check-out, please let me know and I’ll check the availability for you.”
Guest: “Can you recommend a good place for breakfast nearby?” Rumi: “Of course! There’s a wonderful café called Sunrise Bistro just around the corner. They serve delicious breakfast and freshly brewed coffee. Would you like directions?”
Guest: “I need extra pillows and a blanket in my room.” Rumi: “Absolutely, I’ll have extra pillows and a blanket sent to your room right away. Is there anything else I can assist you with?”
<context>
{context}
</context>
"""

@app.route('/query', methods=['POST'])
def query_document():
    query_text = request.form.get('query')
    session_id = request.form.get('session_id')
    
    # If no session ID is provided, create a new session
    if not session_id:
        session_id = session_manager.create_session()
        print('new session id is ' + session_id)
    
    try:
        response = hotelgraph.invoke(
            {'messages': [HumanMessage(content=query_text)]},
            {"configurable": {"thread_id": session_id}}
            )
        
        # Extract the assistant's response
        assistant_response = response['messages'][-1].content
        
        # Return both the response and session ID
        return jsonify({
            "html": f"<p>{assistant_response}</p>",
            "session_id": session_id
        })
        
    except Exception as e:
        print(f"Error in query_document: {str(e)}")  # Debugging
        # If there's an error, make sure to close the session
        session_manager.close_session(session_id)
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@app.route('/close_session', methods=['POST'])
def close_session():
    session_id = request.form.get('session_id')
    if session_id:
        try:
            session_manager.close_session(session_id)
            return jsonify({"status": "success"})
        except Exception as e:
            print(f"Error in close_session route: {str(e)}")
            return jsonify({"status": "error", "message": str(e)}), 500
    return jsonify({"status": "error", "message": "No session ID provided"}), 400
    

    

        
if __name__ == '__main__':
    app.run(host='157.173.210.15', port=4001,debug=True) #When run locally
    #app.run(host="0.0.0.0", port=5000,debug=True) # use with ngroq