#!/usr/bin/env python3
import os
import curses
import argparse
import openai
import pinecone
from dotenv import load_dotenv
import textwrap

load_dotenv()

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
assert OPENAI_API_KEY, "OPENAI_API_KEY environment variable is missing from .env"

PINECONE_API_KEY = os.getenv("PINECONE_API_KEY", "")
assert PINECONE_API_KEY, "PINECONE_API_KEY environment variable is missing from .env"

PINECONE_ENVIRONMENT = os.getenv("PINECONE_ENVIRONMENT", "us-east1-gcp")
assert PINECONE_ENVIRONMENT, "PINECONE_ENVIRONMENT environment variable is missing from .env"

# Table config
PINECONE_TABLE_NAME = os.getenv("TABLE_NAME", "")
assert PINECONE_TABLE_NAME, "TABLE_NAME environment variable is missing from .env"

# Function to query records from the Pinecone index
def query_records(index, query, top_k=1000):
    results = index.query(query, top_k=top_k, include_metadata=True)
    return [{"name": f"{task.metadata['task']}", "result": f"{task.metadata['result']}"} for task in results.matches]

# Get embedding for the text
def get_ada_embedding(text):
    return openai.Embedding.create(input=[text], model="text-embedding-ada-002")["data"][0]["embedding"]

def draw_tasks(stdscr, tasks, scroll_pos, selected):
    y = 0
    h, w = stdscr.getmaxyx()
    for idx, task in enumerate(tasks[scroll_pos:], start=scroll_pos):
        if y >= h:
            break
        task_name = f'{task["name"]}'
        truncated_str = task_name[:w-1]
        if idx == selected:
            stdscr.addstr(y, 0, truncated_str, curses.A_REVERSE)
        else:
            stdscr.addstr(y, 0, truncated_str)
        y += 1

def draw_result(stdscr, task):
    task_name = f'Task: {task["name"]}'
    task_result = f'Result: {task["result"]}'

    _, w = stdscr.getmaxyx()
    task_name_wrapped = textwrap.wrap(task_name, width=w)

    for i, line in enumerate(task_name_wrapped):
        stdscr.addstr(i, 0, line)
    
    y, _ = stdscr.getyx()
    stdscr.addstr(y+1, 0, '------------------')
    stdscr.addstr(y+2, 0, task_result)

def draw_summary(stdscr, objective, tasks, start, num):
    stdscr.box()
    summary_text = f'{len(tasks)} tasks ({start}-{num}) | {objective}'
    stdscr.addstr(1, 1, summary_text[:stdscr.getmaxyx()[1] - 2])

def main(stdscr):
    # Configure OpenAI
    openai.api_key = OPENAI_API_KEY

    # Initialize Pinecone
    pinecone.init(api_key=PINECONE_API_KEY)

    # Connect to the objective index
    index = pinecone.Index(PINECONE_TABLE_NAME)

    curses.curs_set(0)
    stdscr.timeout(1000)

    h, w = stdscr.getmaxyx()
    left_w = w // 2
    visible_lines = h - 3

    scroll_pos = 0
    selected = 0

    # Parse command-line arguments
    parser = argparse.ArgumentParser(description="Query Pinecone index using a string.")
    parser.add_argument('objective', nargs='*', metavar='<objective>', help='''
    main objective description. Doesn\'t need to be quoted.
    if not specified, get objective from environment.
    ''', default=[os.getenv("OBJECTIVE", "")])
    args = parser.parse_args()

    # Query records from the index
    objective = ' '.join(args.objective).strip().replace("\n", " ")
    retrieved_tasks = query_records(index, get_ada_embedding(objective))

    while True:
        stdscr.clear()
        draw_tasks(stdscr.subwin(h-3, left_w, 0, 0), retrieved_tasks, scroll_pos, selected)
        draw_result(stdscr.subwin(h, w - left_w, 0, left_w), retrieved_tasks[selected])
        draw_summary(stdscr.subwin(3, left_w, h - 3, 0), objective, retrieved_tasks, scroll_pos+1, scroll_pos+h-3)

        stdscr.refresh()
        key = stdscr.getch()

        if key == ord('q') or key == 27:
            break
        elif key == curses.KEY_UP and selected > 0:
            selected -= 1
            if selected < scroll_pos:
                scroll_pos -= 1
        elif key == curses.KEY_DOWN and selected < len(retrieved_tasks) - 1:
            selected += 1
            if selected - scroll_pos >= visible_lines:
                scroll_pos += 1

curses.wrapper(main)