import requests
import json
import math
import random
import statistics
import string
import re
from datetime import datetime, date, timedelta
from collections import Counter
from functools import reduce
from difflib import SequenceMatcher
from textwrap import wrap, fill
from itertools import permutations, combinations
import unicodedata

# Global clipboard to store results - only fills once
clipboard = None

def ask_ollama(prompt):
    response = requests.post('http://localhost:11434/api/generate', 
        json={"model": "qwen2.5-coder:7b", "prompt": prompt, "stream": False})
    result = response.json()['response'].strip()
    # Strip markdown code blocks if present
    result = result.replace("```python", "").replace("```", "").strip()
    return result

def create_function():
    print("\nDescribe a function that takes a list of parameters called 'params':")
    print("(You can also reference 'clipboard' which contains the previous result)")
    description = input()
    
    prompt = f"""Write a Python lambda that takes a single parameter called params (a list).
A variable called 'clipboard' contains the previous result and can be used directly.
It should: {description}
Return ONLY the lambda, no explanation, no markdown. 
Example format: lambda params: params[0] + params[1]
Example using clipboard: lambda params: sorted(clipboard)"""
    
    generated_code = ask_ollama(prompt)
    print(f"\nGenerated: {generated_code}\n")
    return generated_code

# Create first function
func_code = create_function()

print("Function loaded! Enter parameters one at a time.")
print("Commands: empty line = execute, 'new' = new function, 'clear' = clear clipboard, 'quit' = exit")
print("The first result is saved to 'clipboard' and stays until cleared.\n")

# Build the globals dict for eval - include all imported modules
eval_globals = {
    "math": math,
    "random": random,
    "statistics": statistics,
    "string": string,
    "re": re,
    "datetime": datetime,
    "date": date,
    "timedelta": timedelta,
    "Counter": Counter,
    "reduce": reduce,
    "SequenceMatcher": SequenceMatcher,
    "wrap": wrap,
    "fill": fill,
    "permutations": permutations,
    "combinations": combinations,
    "unicodedata": unicodedata,
    "open": open,
    "json": json,
    "clipboard": clipboard
}

while True:
    params = []
    print("Enter parameters:")
    
    while True:
        value = input(f"  param[{len(params)}]: ").strip()
        
        if value.lower() == "quit":
            print("Done!")
            exit()
        
        if value.lower() == "clear":
            clipboard = None
            eval_globals["clipboard"] = clipboard
            print("Clipboard cleared!\n")
            break
        
        if value.lower() == "new":
            func_code = create_function()
            print("New function loaded!\n")
            break
            
        if value == "":
            break
        
        # Try to convert to number, otherwise keep as string
        try:
            if '.' in value:
                params.append(float(value))
            else:
                params.append(int(value))
        except ValueError:
            params.append(value)
    
    if value.lower() in ["new", "clear"]:
        continue
    
    if len(params) == 0 and value.lower() != "new":
        # Allow execution with no params (for clipboard-only operations)
        pass
        
    print(f"Calling with: {params}")
    
    # Update clipboard in eval_globals before each execution
    eval_globals["clipboard"] = clipboard
    
    try:
        op = eval(func_code, eval_globals)
        result = op(params)
        
        # Only save to clipboard if it's empty
        if clipboard is None:
            clipboard = result
            eval_globals["clipboard"] = clipboard
            print(f"Result: {result}")
            print(f"(Saved to clipboard)\n")
        else:
            print(f"Result: {result}")
            print(f"(Clipboard unchanged - use 'clear' to reset)\n")
    except Exception as e:
        print(f"Error: {e}\n")
