import os
import base64
from datetime import datetime
import shutil
from openai import OpenAI
import json
from typing import Dict, List

# Load the API key from an environment variable
api_key = "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"
if not api_key:
    raise ValueError("No OpenAI API key found. Please set the OPENAI_API_KEY environment variable.")

# Initialize the OpenAI client
client = OpenAI(api_key=api_key)

# Add this global variable to store facts
stored_facts: Dict[str, str] = {}

def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode('utf-8')

def process_command(user_command, image_path, elements, current_state, action_history, template=None):
    global stored_facts

    # Save a copy of the image
    save_dir = os.path.join(os.path.dirname(__file__), 'sent_to_gpt')
    os.makedirs(save_dir, exist_ok=True)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    save_path = os.path.join(save_dir, f"sent_image_{timestamp}.png")
    shutil.copy(image_path, save_path)

    base64_image = encode_image(image_path)

    elements_description = "\n".join([f"Element {e['id']}: Bounding box {e['bbox']}" for e in elements])

    template_content = f"\nTemplate instructions:\n{template}" if template else ""

    # Add stored facts to the system message
    facts_description = "\n".join([f"{key}: {value}" for key, value in stored_facts.items()])
    facts_content = f"\nStored facts:\n{facts_description}" if stored_facts else ""

    main_agent_response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": f"""
                You are an AI assistant that analyzes screenshots and user commands to determine appropriate actions. 
                The screenshot has been processed to identify potential clickable elements, which are numbered and outlined in red.
                Your task is to interpret the user's command, the screenshot, and the current state to determine the next 1-6 actions to take.
                Figure out your current state: what app are you in? what are you doing? what is the next step?

                If you are in a Google Sheet, Excel, or similar spreadsheet, you must return ONLY ONE action:
                {{"action": "use_google_sheets_agent", "target": null, "value": "<description of what needs to be done in the spreadsheet>"}}

                For all other cases, provide a JSON-formatted array of 1-10 actions. Each action should have the following fields: 
                action (e.g., 'click', 'type', 'hotkey', 'approximate_click', 'store_fact', 'drag', 'hover', 'zoom'), target (the element number to interact with, null, or text to click on), and value 
                (the text to type, the hotkey combination, or null if not applicable).

                Available actions:
                - click: Click on a specific numbered element. Set target to the element number and value to null.
                - type: Type text. If typing into a specific element, set target to the element number; otherwise set target to null. Set value to the text to type.
                - hotkey: Perform a keyboard shortcut. Set target to null and value to the key combination (e.g., "ctrl+t" for new tab, "enter" for submit).
                - approximate_click: Click on text that isn't associated with a numbered element. Set target to the text to click on and value to null.
                - store_fact: Store useful facts about the task. Set target to the fact's key and value to the fact's value.
                - drag: Drag from one element to another. Set target to the starting element number and value to the ending element number.
                - hover: Hover over a specific element. Set target to the element number and value to null.
                - zoom: Zoom in or out. Set target to null and value to "in" or "out".

                When using the store_fact action, choose meaningful keys and values that will be useful for future steps.

                Tips:
                1. When you see a form, aim for the placeholder text.
                2. If you are in a list of results, choose the most relevant result.
                3. Search bars are usually on top of the page somewhere.
                4. If there is any highly relevant information to the user's task, e.g. if they say "this event" or "that item", or "this candidate", please extract that information from the image or task and store it using store_fact (e.g. the name of the event, or the name of the candidate), as you may need it later.

                Important Rules: 
                1. If the required elements or website are not visible in the current screenshot, take proactive steps to navigate to the correct page or open a new tab.
                2. Provide actions in batches. Do not make assumptions about things you can't see in the current screenshot.
                3. After each batch of actions, indicate whether more actions will be needed or if the task is complete.
                4. For tasks involving logging into websites, always start by opening a new tab and navigating to the website's login page if it's not already visible.
                5. Provide specific, actionable steps. Do not suggest manual actions or ask for more information unless absolutely necessary.
                6. After suggesting actions, indicate whether the task is complete or if further steps will be needed.

                Always provide at least one action unless the task is explicitly complete.

                Available elements:
                {elements_description}

                Current user command: {user_command}
                Current state: {current_state}
                Action history: {action_history}
                Helpful context/task template: {template_content}
                Facts about the task: {facts_content}
                """
            },
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": f"What should I do next to accomplish the task: {user_command}"},
                    {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}}
                ]
            }
        ],
        max_tokens=800,
        timeout=120
    )

    content = main_agent_response.choices[0].message.content
    print("Raw GPT response:", content)  # Debug print

    # Extract actions from the content
    actions = extract_actions_from_content(content)

    if not actions:
        print("No actions provided, generating a default action")
        actions = [{"action": "type", "target": None, "value": "No specific action could be determined. Please provide more context or a clearer command."}]

    print("Parsed actions:", actions)  # Debug print

    # Check if we need to use the Google Sheets agent
    if len(actions) == 1 and actions[0]['action'] == 'use_google_sheets_agent':
        return handle_google_sheets_task(actions[0]['value'], base64_image)

    # Process the actions
    final_actions = []
    for action in actions:
        if action['action'] == 'store_fact':
            stored_facts[action['target']] = action['value']
        final_actions.append(action)

    task_complete = "task complete" in content.lower() or "task is complete" in content.lower()

    return {
        "thoughts": content,
        "actions": final_actions,
        "task_complete": task_complete
    }

def handle_google_sheets_task(task_description, base64_image):
    print("Handling Google Sheets task:", task_description)
    google_sheets_response = consult_google_sheets_agent(task_description, base64_image)
    
    print("Google Sheets agent response:", google_sheets_response)
    actions = extract_actions_from_content(google_sheets_response)
    
    return {
        "thoughts": google_sheets_response,
        "actions": actions,
        "task_complete": False  # Assume task is not complete after one round of Google Sheets actions
    }

def extract_actions_from_content(content):
    try:
        # Try to parse the entire content as a JSON object or array
        parsed_content = json.loads(content)
        if isinstance(parsed_content, list):
            return parsed_content
        elif isinstance(parsed_content, dict):
            return [parsed_content]  # Return a list containing the single action
    except json.JSONDecodeError:
        # If parsing the entire content fails, try to extract JSON objects
        import re
        json_objects = re.findall(r'\{[^{}]*\}', content)
        actions = []
        for json_obj in json_objects:
            try:
                action = json.loads(json_obj)
                if all(key in action for key in ['action', 'target', 'value']):
                    actions.append(action)
            except json.JSONDecodeError:
                continue
        return actions

    return []  # Return an empty list if no valid actions were found

def consult_google_sheets_agent(task_description, base64_image):
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": """
                You are a Google Sheets expert. Your task is to provide specific actions to perform in Google Sheets using keyboard shortcuts and efficient techniques. Here are some important rules:

                1. To navigate to a specific cell, use the hotkey "ctrl+j", then type the cell reference (e.g., "C2"), then press "enter".
                2. To bold or italicize a cell after typing into it, use "ctrl+j" to navigate back to it, then use "ctrl+b" for bold or "ctrl+i" for italics.
                3. To move to a cell below, use the "enter" key (not "shift+enter"). To move right, use "tab". For left or up, use arrow keys.
                4. Do not use "ctrl+enter" or "ctrl+shift" for anything.

                Analyze the provided screenshot and task description. Then provide a JSON-formatted array of actions to complete the task. Each action should have the following fields:
                - action: The type of action (e.g., 'navigate', 'type', 'hotkey')
                - target: The cell reference or null
                - value: The text to type, formula, or hotkey combination

                Example:
                [
                    {"action": "navigate", "target": "A1", "value": null},
                    {"action": "type", "target": null, "value": "Header"},
                    {"action": "hotkey", "target": null, "value": "ctrl+b"}
                ]
                """
            },
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": task_description},
                    {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}}
                ]
            }
        ],
        max_tokens=800,
        timeout=120
    )

    return response.choices[0].message.content