import pathlib
from langchain_community.vectorstores import FAISS
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

QUERY_PROMPT = """You are a technical advisor with expertise using the Portainer API.
When a user asks for a question related to Portainer, describe how to use the Portainer API to achieve their goal.
Include a curl request example in each of your answer. When multiple requests are needed, include a curl example for each request required.

For API endpoints with authentication required, use the API token based authentication and always assume that the user already has a token that they can include. The API token can be specified via the x-api-key HTTP header.

Use the sub-path /endpoints/{{id}}/docker/ to send Docker API requests and /endpoints/{{id}}/kubernetes/ to send Kubernetes API requests. Examples:

* /endpoints/{{id}}/docker/containers/json or /endpoints/{{id}}/docker/volumes
* /endpoints/{{id}}/kubernetes/namespaces/{{namespace}}/pods or /endpoints/{{id}}/kubernetes/deployments

Answer the question based only on the following context which contains the documentation of the API: 
{context}

Question: {question}"""

def process_query(queries):
    """
    Processes a list of queries related to Portainer API usage by constructing a specialized prompt. The function 
    leverages a retriever model to fetch relevant context from a local FAISS vector store. It then uses this context 
    and a large language model to generate comprehensive responses that include curl request examples for interacting 
    with the Portainer API.

    This function constructs a prompt that positions the model as a technical advisor with expertise in the Portainer 
    API. It includes instructions for the model to always use API token-based authentication and to utilize specific 
    sub-paths for Docker and Kubernetes API requests. The prompt also incorporates context provided by the retriever 
    model. Responses are designed to be accurate and context-aware, providing specific curl request examples for each 
    part of the query.

    :param queries: A list of strings, where each string represents a user's query related to the Portainer API.
    :return: A response generated by the model.

    The function creates a query from the list of queries, uses a FAISS vector store to retrieve relevant context, 
    constructs a specialized prompt with this context, and then uses a large language model to generate a response.
    """
    query = "\n".join(queries)
    
    data_path = pathlib.Path.home() / '.portainerlang/faiss'
    vectorstore = FAISS.load_local(data_path, embeddings=OpenAIEmbeddings())
    retriever = vectorstore.as_retriever()

    prompt = ChatPromptTemplate.from_template(QUERY_PROMPT)
    model = ChatOpenAI(model_name="gpt-4-1106-preview", temperature=0)

    rag_chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | model
        | StrOutputParser()
    )

    response = rag_chain.invoke(query)
    return response
