"""
    NOTE: THIS APPLICATION IS PROVIDED FOR DEMONSTRATION AND LEARNING PURPOSES.
    INFORMATION GENERATED AND PROVIDED BY THIS APPLICATION MAY NOT BE FACTUAL.
    ALWAYS CONFIRM IMPORTANT INFORMATION GENERATED BY THIS APPLICATION.

    This application aims to leverage LLMs to provide useful support information
    on various aspects of life in the United States to persons who have 
    immigrated into the country. Information available includes:

    - general description of how to get a drivers license
    - common procedure for opening a savings account, and a checking account
    - how to find and rent an apartment
    - tips on buying a car, and how to avoid being taken advantage of by a dealer
    - various types of visas

    This application makes use of function tools made available to the LLM
    to carry out these various tasks.

    This project uses the uv virtual environment.

    pip install uv

    uv run main.py

    You need a file named .env with a key OPENAI_API_KEY whose value is
    your OpenAI API key.
"""

import os
import json
import gradio as gr
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv(override=True)
openai = OpenAI()    

openai_api_key = os.getenv('OPENAI_API_KEY')

if openai_api_key:
    print(f"OpenAI API Key exists and begins {openai_api_key[:8]}")
else:
    print("OpenAI API Key not set - please head to the troubleshooting guide in the setup folder")


def getting_drivers_license():
    system_prompt = "You are a helpful assistant whose job is to search the web for general information on how to get a drivers license in the United States. " 
    "Although the steps to get a drivers license may vary by state, there are common procedures that can be listed. "
    "Provide as much detail as you can, listing relevant steps typically required to get a drivers license, such as passing a written exam, "
    "passing an eye sight exam, and passing a driving exam in which you drive around town with a tester who gives instructions "
    "and evaluates the subject's performance, possibly failing them if they make a serious mistake."
    "But you should search the web to ensure you get sufficient information."

    messages = [{"role": "system", "content": system_prompt}]
    response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
    return response.choices[0].message.content

def opening_savings_account_or_checking_account():
    system_prompt = "You are a helpful assistant whose job is to search the web for general information on how to open a savings account or a checking account in the United States. " 
    "Although the steps to such accounts may vary by state, there are common aspects can be listed. "
    "Provide as much detail as you can, listing relevant steps typically required to open these accounts. "
    "Also gather details about savings and checking accounts that may be useful to users."
    "But you should search the web to ensure you get sufficient information."

    messages = [{"role": "system", "content": system_prompt}]
    response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
    return response.choices[0].message.content

def find_and_rent_apartment():
    system_prompt = "You are a helpful assistant whose job is to search the web for general information on how to find and rent an apartment in the United States. " 
    "Although the steps to find and rent an apartment may vary by state, city, and locale, there are common procedures that can be listed. "
    "Provide as much detail as you can, listing relevant steps typically required, such as checking online sites for available listings, "
    "checking bulletin boards in universities, libraries, grocery stores, etc. Mentions steps such as the practice of providing first and last "
    "months rent in advance, and one months rent security deposit, but also mention that the requirements are not fixed and can vary greatly. "
    "But you should search the web to ensure you get sufficient information."

    messages = [{"role": "system", "content": system_prompt}]
    response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
    return response.choices[0].message.content

def buying_a_car_json():
    system_prompt = "You are a helpful assistant whose job is to search the web for general information on how to buy a car in the United States. " 
    "Although the steps to buy a car may vary by state, there are common procedures that can be listed. "
    "Provide as much detail as you can, listing relevant tasks that are carried out when buying a car, such as stopping by a car dealer, "
    "looking on Craigslist and Facebook Marketplace, and other online sources. Also mention the need to make a down payment, secure financing, "
    "or to pay by cash. Mention the need to secure insurance, and the need to register the vehicle. "
    " Also give hints on how to avoid being taken advantage of by unscrupulous sales persons. "
    "But you should search the web to ensure you get sufficient information."

    messages = [{"role": "system", "content": system_prompt}]
    response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
    return response.choices[0].message.content

def types_of_visas_json():
    system_prompt = "You are a helpful assistant whose job is to search the web for general information on the types of visas in the United States. " 
    "There are a large number of visa available to immigrants who satisfy various conditions, and you cannot comment on all aspects of visas, "
    "but you should gather useful information and provide it to users. "
    "But you should search the web to ensure you get sufficient information."

    messages = [{"role": "system", "content": system_prompt}]
    response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
    return response.choices[0].message.content

def main():
    getting_drivers_license_json = {
        "name": "getting_drivers_license",
        "description": (
            "Use this tool to search the web for general information on how to get a drivers license in the United States. " 
            "Although the steps to get a drivers license may vary by state, there are common procedures that can be listed."
        )
    }

    opening_savings_account_or_checking_account_json = {
        "name": "opening_savings_account_or_checking_account",
        "description": (
            "Use this tool to search the web for general information on how to open a savings account and how to open a checking account in the United States. " 
            "Although opening a savings or checking account may vary by state, there are common procedures that can be listed."
        )
    }

    find_and_rent_apartment_json = {
        "name": "find_and_rent_apartment",
        "description": (
            "Use this tool to search the web for general information on how to find and rent an apartment in the United States. " 
            "Although the steps to may vary by state, city or locale, there are common procedures that can be listed."
        )
    }

    buying_a_car_json = {
        "name": "buying_a_car",
        "description": (
            "Use this tool to search the web for general information on how to buy a car in the United States. "
            "For example you typically need to make a down payment and get financing, or pay cash. "
            "You need to get insurance, get the car registered, etc."
            "Also find and provide tips on how to not get cheated by a car salesman, as it is a problem, "
            "especially for immigrants who are often taken advantage of by unscrupulous sales persons." 
            "Although the steps to get a drivers license may vary by state, there are common procedures that can be listed."
        )
    }

    types_of_visas_json = {
        "name": "types_of_visas",
        "description": (
            "Use this tool to search the web for general information on the types of visas available to immigrants in the United States. " 
            "Although the steps to get a drivers license may vary by state, there are common procedures that can be listed."
        )
    }

    tools = [
        {"type": "function", "function": getting_drivers_license_json},
        {"type": "function", "function": opening_savings_account_or_checking_account_json},
        {"type": "function", "function": find_and_rent_apartment_json},
        {"type": "function", "function": buying_a_car_json},
        {"type": "function", "function": types_of_visas_json}
    ]

    def chat(message, history):
        system_prompt = f"You are a helpful assistant providing support services to immigrants new to the United States. \
        You can use the tools made available to you to search the web for relevant information and provide the found " \
        "information to the user. If you do not know the answer to a question, or you do not have a tool designed to " \
        "get the information, simply tell the user you do not know. Do not provide information if you do not have a " \
        "tool to use in getting the information."

        messages = [{"role": "system", "content": system_prompt}] + history + [{"role": "user", "content": message}]
        done = False

        while not done:
            response = openai.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)

            finish_reason = response.choices[0].finish_reason
             
            if finish_reason=="tool_calls":
                message = response.choices[0].message
                tool_calls = message.tool_calls
                results = handle_tool_calls(tool_calls)
                messages.append(message)
                messages.extend(results)
            else:
                done = True
        return response.choices[0].message.content

    def handle_tool_calls(tool_calls):
        results = []
        for tool_call in tool_calls:
            tool_name = tool_call.function.name
            arguments = json.loads(tool_call.function.arguments)
            print(f"Tool called: {tool_name}", flush=True)
            tool = globals().get(tool_name)
            result = tool(**arguments) if tool else {}
            results.append({"role": "tool","content": json.dumps(result),"tool_call_id": tool_call.id})
        return results

    WELCOME = ("Welcome to the Alpha Centauri Immigrant Support Center! \n"
    "I can provide information on the following topics: \n"
    "- getting a drivers license\n"
    "- opening a savings/checking account\n"
    "- finding and renting an apartment\n"
    "- buying a car\n"
    "- types of visas in the United States")

    chatbot = gr.Chatbot(value=[{"role": "assistant", "content": WELCOME}], type="messages", height=750,);
    gr.ChatInterface(chat, chatbot=chatbot, type="messages").launch(inbrowser=True);

if __name__ == "__main__":
    main()
