#%%
import os
from io import BytesIO
import elevenlabs
import openai
import random
import dotenv
import subprocess
import threading
import time

dotenv.load_dotenv()

elevenlabs.set_api_key(os.getenv("ELEVENLABS_API_KEY"))

VOICE_HOST = os.getenv("VOICE_HOST", "Adam")
VOICE_USER = os.getenv("VOICE_USER", "Bella")



def say(line, voice=VOICE_HOST):
    audio_stream = elevenlabs.generate(
        text=line.replace(" ett ", " en "),
        voice=voice,
        model="eleven_multilingual_v1",
        stream=True
    )

    elevenlabs.stream(audio_stream)



def transcribe_audio(audio_data):
    wav_data = BytesIO(audio_data.get_wav_data())
    wav_data.name = "SpeechRecognition_audio.wav"

    transcript = openai.Audio.transcribe(
        model="whisper-1", 
        file=wav_data, 
        api_key=os.getenv("OPENAI_API_KEY"), 
        language="sv",
        prompt=None,
        )
    
    text = transcript["text"]

    print(f"User said: {text}")

    if len(text.strip()) > 0:
        add_user_message(text)

    return transcript


def add_user_message(message):
    global messages
    messages.append({"role": "user", "content": message})


def add_assistant_message(message):
    global messages
    messages.append({"role": "assistant", "content": message})


def gpt():
    global messages

    response = openai.ChatCompletion.create(
        api_key=os.getenv("OPENAI_API_KEY"),
        model="gpt-3.5-turbo",
        # model="gpt-4",
        messages=messages,
        temperature=1.2,
        top_p=1,
        frequency_penalty=0.5,
        presence_penalty=0.5,
        max_tokens=200,
    )

    text = response.choices[0].message.content
    return text

def assistant(line, do_say=True):
    add_assistant_message(line)
    print(f"Spelmästare: {line}")
    if do_say:
        say(line)

def player(line, do_say=True):
    add_user_message(line)
    print(f"Du: {line}")
    if do_say:
        say(line, VOICE_USER)




def stream_until(event, audio_stream):
    mpv_command = ["mpv", "--no-cache", "--no-terminal", "--", "fd://0"]
    mpv_process = subprocess.Popen(
        mpv_command,
        stdin=subprocess.PIPE,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )

    for chunk in audio_stream:
        if event.is_set():
            mpv_process.stdin.close()
            mpv_process.kill()
            return
        if chunk is not None:
            mpv_process.stdin.write(chunk)
            mpv_process.stdin.flush()
        
    if mpv_process.stdin:
        mpv_process.stdin.close()
    mpv_process.wait()


def play_file_until(event, filename):
    mpv_command = ["mpv", "--no-cache", "--no-terminal", "--volume=53", "--", filename]
    mpv_process = subprocess.Popen(
        mpv_command,
        stdin=subprocess.PIPE,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )

    if event.wait(5):
        mpv_process.stdin.close()
        mpv_process.kill()
        return

    if mpv_process.stdin:
        mpv_process.stdin.close()
    mpv_process.wait()


bgm_stop_event = threading.Event()
bgm_thread = None
bgm_path = "bgm.mp3"

def start_bgm():
    global bgm_thread
    global bgm_stop_event

    bgm_stop_event.clear()
    bgm_thread = threading.Thread(target=play_file_until, args=(bgm_stop_event, bgm_path,))
    bgm_thread.start()


def stop_bgm():
    global bgm_thread
    global bgm_stop_event

    if bgm_thread is not None:
        bgm_stop_event.set()
        bgm_thread.join()



prompt = """
You are benovelent, nihilistic, and funny role playing game host. 
You respond very concisely concisely. 
If you don't know the answer to a question, you make something up on the spot. 
You are adept at english and swedish. You respond very concisely.
You are very concise in your writing. 
The game is very short and moves quickly. The interactions are simple. 
"""


messages = [
    {"role": "system", "content": prompt},
]


say("Välkommen till spelet 'Otrolig Magisk Grotta Tre punkt Noll'. Bered dig på trubbel.")

start_bgm()

say("Välj svårighetsgrad. Alternativ: lätt, medel, svår, extrem, galen, omöjlig, fruktansvärd, dödlig, dödligare, dödligast, dödligastast, dödligastastast, dödligastastastast, dödligastastastastast, dödligastastastastastast, dödligastastastastastastast, dödligasta")
print("""
1) Lätt
2) Medel
3) Svår
4) Extrem
5) Galen
6) Omöjlig
7) Fruktansvärd
8) Dödlig
9) Dödligare
10) Dödligast
11) Dödligastast
etc..
""")

difficulty = int(input())


add_assistant_message("Välkommen till spelet 'Otrolig Magisk Grotta Tre punkt Noll'. Vackra monster som dyker upp i spelet: Dunsorr, BKC, Znurre, Kwarf, Lokomotii'Vet")
assistant("Du befinner dig i grotta. Du vaknar upp och är groggy.", True)
assistant("Du möter en hund. Vad gör du med hund?", True)


playing = True
turn = 0
while playing:
    turn += 1

    i = input()
    
    if len(i.strip()) == 0:
        assistant("Hoppsan du dödades. lol", True)
        break
    
    player(i)

    if turn > (7 - difficulty) and random.random() < (difficulty * 0.2):
        stop_bgm()
        assistant("Hoppsan du dödades. lol", True)
        break

    assistant(gpt(), True)

start_bgm()

assistant("""Tack för att du spelade Otrolig Magisk Grotta Tre punkt Noll. 
Greets till: Hund, fejsrape, betvå, achtung fulkod, ph4 labs, bingbong, Oh Jay, Husvagnkru, killen på rad sex. 
...
Njut av birdie! Hehu""", True)

stop_bgm()