# self_build.py

from functionz.core.framework import func
import json

@func.register_function(
    metadata={"description": "Generates queries based on user description"},
    dependencies=["gpt_call"],
    imports=["json"]
)
def generate_queries(user_description, X=3, max_retries=3):
    """
    Generates X distinct queries that require action based on the user description using gpt_call. 

    Args:
        user_description (str): Description of the user or their needs.
        X (int, optional): Number of queries to generate. Defaults to 3.
        max_retries (int, optional): Maximum number of retries for generating valid queries. Defaults to 3.

    Returns:
        list: A list of generated queries.

    Raises:
        ValueError: If unable to generate valid queries within the retry limit.
    """
    prompt = f"""
You are an AI assistant. Based on the following user description, generate {X} distinct queries that such a user might ask:

User Description:
"{user_description}"

Provide the queries in JSON format as a list:

[
  "Query 1",
  "Query 2",
  ...
]

Ensure the queries are diverse, relevant to the user description, and represent realistic questions that this user might ask. Make requests that require action, such as using tools and APIs, which you should specify in the request. Based on the user description, guess what types of tools they use and specify them in the query.
"""

    errors = []  # To collect error messages from each attempt

    for attempt in range(1, max_retries + 1):
        response = gpt_call(prompt)
        try:
            queries = json.loads(response)
            if isinstance(queries, list) and len(queries) == X and all(isinstance(q, str) for q in queries):
                return queries
            else:
                error_message = (
                    f"Attempt {attempt}: Invalid JSON structure or incorrect number of queries. "
                    f"Expected {X} string queries, but received: {response}"
                )
                errors.append(error_message)
        except json.JSONDecodeError as e:
            error_message = (
                f"Attempt {attempt}: JSON decoding failed with error: {str(e)}. "
                f"Response received: {response}"
            )
            errors.append(error_message)
        except Exception as e:
            error_message = (
                f"Attempt {attempt}: An unexpected error occurred: {str(e)}. "
                f"Response received: {response}"
            )
            errors.append(error_message)

    # After all attempts, raise an error with all collected messages
    full_error_message = " | ".join(errors)
    raise ValueError(f"Failed to generate {X} valid queries after {max_retries} attempts. Errors: {full_error_message}")


@func.register_function(
    metadata={"description": "Processes generated queries based on user description"},
    dependencies=["generate_queries", "process_user_input"],
    imports=["json"]
)
def self_build(user_description, X=3):
    """
    Generates queries based on the user description and processes each query.

    Args:
        user_description (str): Description of the user or their needs.
        X (int, optional): Number of queries to generate and process. Defaults to 3.

    Returns:
        list: A list of dictionaries containing each query and its corresponding output.

    Raises:
        ValueError: If query generation fails.
    """
    try:

        print("\033[1;33mUser Description: ", user_description, "\033[0m")
        # Generate queries
        queries = generate_queries(user_description, X)
    except ValueError as e:
        # Log the error message for debugging
        print(f"Error in generate_queries: {str(e)}")
        return []

    print("\033[1;34mQueries generated by self_build: ", queries, "\033[0m")
    results = []
    for idx, query in enumerate(queries, start=1):
        try:
            output = process_user_input(query)
            results.append({'query': query, 'output': output})
        except Exception as e:
            # Log the error message for debugging
            print(f"Error processing query {idx} ('{query}'): {str(e)}")
            results.append({'query': query, 'output': None, 'error': str(e)})

    return results
