"""
This module defines the ConversationManager class which facilitates managing
conversations with an OpenAI model.

The ConversationManager class is responsible for maintaining the history of
a conversation, including both user and system messages, and utilizing the
OpenAI API to generate contextually relevant responses based on this history.
It leverages the OpenAI's GPT model to simulate an interactive and empathetic
conversation experience, enhancing user engagement through dynamically
generated responses that reflect an understanding of the conversation context.

The module utilizes the OpenAI API client for communication with OpenAI's
services, and requires a valid API key for authentication. The class supports
setting up the API client, adding messages to the conversation history, and
generating responses from the model. It aims to provide an easy-to-use interface
for integrating advanced conversational AI capabilities into applications.

Classes:
    ConversationManager: Manages conversation interactions with an OpenAI model.

Example usage:
    >>> from conversation_manager import ConversationManager
    >>> conv_manager = ConversationManager(client=openai.Client(), model_name="gpt-3.5-turbo")
    >>> conv_manager.add_user_message("Hello, how are you?")
    >>> response = conv_manager.generate_response()
    >>> print(response)

Author: Ricard Santiago Raigada García
Date: 27/03/24
"""
import openai
from ..config import Config


class ConversationManager:
    """
    Manages conversation interactions with an OpenAI model.

    This class handles the accumulation of messages within a conversation
    and utilizes the OpenAI API to generate responses based on the conversation
    history. It supports adding both user and system messages to the history,
    and uses these messages to generate responses that are contextually relevant.

    Attributes:
        client: The OpenAI API client instance used for generating responses.
        model_name (str): The name of the OpenAI model to be used for generating responses.
        messages (list of dict): A list that stores the history of the conversation.
            Each message in the history is represented as a dictionary with 'role' and 'content' keys.

    Args:
        client: An initialized OpenAI API client.
        model_name (str): The name of the OpenAI model to be used. Defaults to "gpt-3.5-turbo".

    Methods:
        setup_openai(): Configures the OpenAI client with the API key from configuration.
        add_system_message(content): Adds a message from the system to the conversation history.
        add_user_message(content): Adds a message from the user to the conversation history.
        generate_response(): Generates a response from the model based on the conversation history.
    """

    def __init__(self, client, model_name="gpt-3.5-turbo"):
        """
        Initializes the conversation manager with the specified OpenAI client and model.

        Args:
            client: An instance of the OpenAI API client to be used for requests.
            model_name (str): The name of the OpenAI model to be used for generating responses.
        """
        self.client = client
        self.model_name = model_name
        self.messages = []
        self.setup_openai()

    def setup_openai(self):
        """
        Configures the OpenAI client with the API key obtained from the configuration.

        This method sets the API key for the OpenAI client, enabling it to authenticate
        and perform API requests. The API key is retrieved from the application's configuration.
        """
        openai.api_key = Config.get_api_key()

    def add_system_message(self, content):
        """
        Adds a system-generated message to the conversation history.

        Args:
            content (str): The content of the system message to be added.
        """
        self.messages.append({"role": "system", "content": content})

    def add_user_message(self, content):
        """
        Adds a user message to the conversation history.

        Args:
            content (str): The content of the user message to be added.
        """
        self.messages.append({"role": "user", "content": content})

    def generate_response(self):
        """
        Generates a response from the model based on the current conversation history.

        This method sends the accumulated conversation history to the OpenAI API
        and retrieves a contextually relevant response. The response is then added
        to the conversation history as a system message.

        Returns:
            str: The response generated by the OpenAI model.

        Raises:
            ValueError: If an invalid response is received from the OpenAI API.
        """
        try:
            response = self.client.chat.completions.create(
                model=self.model_name,
                messages=self.messages,
                temperature=1,
                max_tokens=4096,
                top_p=0.87,
                frequency_penalty=0,
                presence_penalty=0
            )
            # Add the generated response to the conversation history
            self.add_system_message(response.choices[0].message.content)
            return response.choices[0].message.content

        except openai.error.OpenAIError as e:
            raise ValueError(f"Error when calling OpenAI API: {str(e)}")
