import os
import sys
import subprocess
import tkinter as tk
from tkinter import scrolledtext, messagebox, filedialog, ttk
import threading
import sounddevice as sd
import numpy as np
from scipy.io.wavfile import write
from faster_whisper import WhisperModel
import time
import locale

# --- LIBRARY PATH CONFIGURATION ---
base_dir = os.path.dirname(os.path.abspath(__file__))
lib_dir = os.path.join(base_dir, "lib")
if os.path.exists(lib_dir):
    sys.path.insert(0, lib_dir)

from translations import LANG_DATA

# --- GET SYSTEM LANGUAGE SAFELY ---
try:
    locale.setlocale(locale.LC_ALL, "")
    sys_lang_full = locale.getlocale()[0]
    sys_lang = sys_lang_full[:2].lower() if sys_lang_full else 'en'
except Exception:
    sys_lang = 'en'

T = LANG_DATA.get(sys_lang, LANG_DATA['en'])

MODEL_PATH = "/opt/fuss-speechtotext/models"
TEMP_AUDIO = "/tmp/fuss_stt.wav"

class FussListenGUI:
    def __init__(self, root):
        self.root = root
        self.root.title(T['title'])
        
        # --- 1. CENTER WINDOW & RESIZABLE ---
        window_width = 700
        window_height = 850
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        
        # Calculate center coordinates
        center_x = int(screen_width/2 - window_width/2)
        center_y = int(screen_height/2 - window_height/2)
        
        self.root.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')
        self.root.resizable(True, True) # 3. ALLOW RESIZING
        self.root.configure(bg="#e1f3fe")
        
        self.header_bg = "#bdcdd7"
        self.font_bold = ("Arial", 11, "bold")
        
        self.is_recording = False
        self.audio_data = []
        self.model = None
        self.selected_lang = tk.StringVar(value=sys_lang if sys_lang in ['it','de','en','fr'] else "it")

        # --- HEADER ---
        self.header = tk.Frame(root, bg=self.header_bg, pady=15)
        self.header.pack(fill=tk.X)
        tk.Label(self.header, text=T['title'].upper(), bg=self.header_bg, 
                 fg="#4a5a6a", font=("Arial", 16, "bold")).pack()
        tk.Label(self.header, text=T['subtitle'], 
                 bg=self.header_bg, fg="#4a5a6a", font=("Arial", 9, "bold")).pack()

        # --- LANG SELECTOR ---
        self.lang_container = tk.Frame(root, bg="#e1f3fe", pady=10)
        self.lang_container.pack(fill=tk.X)
        self.lang_inner = tk.Frame(self.lang_container, bg="#e1f3fe")
        self.lang_inner.pack()
        tk.Label(self.lang_inner, text=T['label_lang'], bg="#e1f3fe", font=self.font_bold, fg="#4a5a6a").pack(side=tk.LEFT, padx=(0, 15))
        for text, val in [("Italiano", "it"), ("Deutsch", "de"), ("English", "en"), ("Français", "fr")]:
            tk.Radiobutton(self.lang_inner, text=text, variable=self.selected_lang, value=val, 
                           bg="#e1f3fe", activebackground="#e1f3fe", font=("Arial", 10), padx=5).pack(side=tk.LEFT)

        # --- MODE SLIDER ---
        self.slider_container = tk.Frame(root, bg="#e1f3fe", pady=5)
        self.slider_container.pack(fill=tk.X)
        self.slider_inner = tk.Frame(self.slider_container, bg="#e1f3fe")
        self.slider_inner.pack()
        self.beam_slider = tk.Scale(self.slider_inner, from_=1, to=5, orient=tk.HORIZONTAL, 
                                    length=350, bg="#e1f3fe", highlightthickness=0,
                                    showvalue=True, troughcolor="#bdcdd7", activebackground="#6189a6",
                                    command=self.update_description)
        self.beam_slider.set(2)
        self.beam_slider.pack()
        self.desc_slider = tk.Label(root, text="", bg="#e1f3fe", font=("Arial", 9, "italic"), fg="#7f8c8d")
        self.desc_slider.pack(pady=(0, 5))

        # --- STATUS & PROGRESS ---
        self.status_label = tk.Label(root, text=T['status_init'], bg="#e1f3fe", fg="#d35400", font=self.font_bold)
        self.status_label.pack(pady=5)
        self.progress = ttk.Progressbar(root, orient=tk.HORIZONTAL, length=600, mode='determinate')
        self.progress.pack(pady=5)

        # --- TEXT AREA (NOW EXPANDABLE) ---
        self.text_frame = tk.Frame(root, bg="#e1f3fe", padx=40)
        self.text_frame.pack(fill=tk.BOTH, expand=True) # expand=True allows it to grow
        self.text_area = scrolledtext.ScrolledText(self.text_frame, wrap=tk.WORD, font=("Arial", 12), height=10, bd=1, relief="solid")
        self.text_area.pack(fill=tk.BOTH, expand=True)
        
        # Context Menu
        self.context_menu = tk.Menu(self.text_area, tearoff=0)
        self.context_menu.add_command(label=T['menu_cut'], command=lambda: self.text_area.event_generate("<<Cut>>"))
        self.context_menu.add_command(label=T['menu_copy'], command=lambda: self.text_area.event_generate("<<Copy>>"))
        self.context_menu.add_command(label=T['menu_paste'], command=lambda: self.text_area.event_generate("<<Paste>>"))
        self.context_menu.add_separator()
        self.context_menu.add_command(label=T['menu_select_all'], command=self.select_all)
        self.text_area.bind("<Button-3>", lambda e: self.context_menu.tk_popup(e.x_root, e.y_root))

        # --- FOOTER BUTTONS ---
        self.footer = tk.Frame(root, bg="#e1f3fe", padx=40, pady=20)
        self.footer.pack(fill=tk.X, side=tk.BOTTOM)

        self.footer.columnconfigure(0, weight=1, uniform="group1")
        self.footer.columnconfigure(1, weight=1, uniform="group1")

        # Row 1
        self.btn_start = tk.Button(self.footer, text=T['btn_record'], bg="#569d6b", fg="white", font=self.font_bold, relief="flat", command=self.start_recording, state=tk.DISABLED)
        self.btn_start.grid(row=0, column=0, sticky="nsew", padx=30, pady=5, ipady=5)
        self.btn_stop = tk.Button(self.footer, text=T['btn_stop'], bg="#bc6c63", fg="white", font=self.font_bold, relief="flat", command=self.stop_recording, state=tk.DISABLED)
        self.btn_stop.grid(row=0, column=1, sticky="nsew", padx=30, pady=5, ipady=5)

        # Row 2
        self.btn_load = tk.Button(self.footer, text=T['btn_load'], bg="#7a8a99", fg="white", font=self.font_bold, relief="flat", command=self.load_file_dialog, state=tk.DISABLED)
        self.btn_load.grid(row=1, column=0, sticky="nsew", padx=30, pady=5, ipady=5)
        self.btn_clear = tk.Button(self.footer, text=T['btn_clear'], bg="#bdcdd7", fg="#4a5a6a", font=self.font_bold, relief="flat", command=self.clear_text)
        self.btn_clear.grid(row=1, column=1, sticky="nsew", padx=30, pady=5, ipady=5)

        # Row 3: EXIT BUTTON
        self.btn_exit = tk.Button(self.footer, text=T['btn_exit'], bg="#4a5a6a", fg="white", font=self.font_bold, relief="flat", command=self.root.destroy, width=15)
        self.btn_exit.grid(row=2, column=0, columnspan=2, pady=(15, 5), ipady=5)
        
        threading.Thread(target=self.load_model, daemon=True).start()
    
    def update_description(self, val):
        self.desc_slider.config(text=T.get(f'mode_{val}', ""))

    def select_all(self):
        self.text_area.tag_add("sel", "1.0", "end")
        self.text_area.mark_set("insert", "1.0")
        self.text_area.see("insert")
        return "break"

    def clear_text(self):
        if messagebox.askyesno(T['msg_clear_title'], T['msg_clear_body']):
            self.text_area.delete(1.0, tk.END)

    def load_model(self):
        try:
            self.model = WhisperModel(MODEL_PATH, device="cpu", compute_type="int8", cpu_threads=0, num_workers=2)
            self.root.after(0, self.model_ready)
        except Exception as e:
            self.status_label.config(text=f"{T['status_error']}: {e}", fg="red")

    def model_ready(self):
        self.status_label.config(text=T['status_ready'], fg="#27ae60")
        self.btn_start.config(state=tk.NORMAL)
        self.btn_load.config(state=tk.NORMAL)
        self.update_description(2)

    def start_recording(self):
        self.audio_data = []
        self.is_recording = True
        self.btn_start.config(state=tk.DISABLED, bg="#95a5a6")
        self.btn_stop.config(state=tk.NORMAL)
        self.status_label.config(text=T['status_listening'], fg="#c0392b")
        self.progress['value'] = 0
        threading.Thread(target=self.record_loop, daemon=True).start()

    def record_loop(self):
        try:
            with sd.InputStream(device=None, samplerate=16000, channels=1, callback=lambda i,f,t,s: self.audio_data.append(i.copy())):
                while self.is_recording: sd.sleep(100)
        except Exception as e:
            self.is_recording = False
            self.root.after(0, lambda: messagebox.showerror("Audio Error", str(e)))

    def stop_recording(self):
        self.is_recording = False
        self.btn_stop.config(state=tk.DISABLED)
        self.status_label.config(text=T['status_processing'], fg="#2980b9")
        self.progress.start(10)
        threading.Thread(target=self.process_audio, daemon=True).start()

    def process_audio(self):
        if not self.audio_data: return
        audio = np.concatenate(self.audio_data, axis=0)
        if np.max(np.abs(audio)) < 0.01:
            self.root.after(0, self.audio_silent)
            return
        write(TEMP_AUDIO, 16000, audio)
        self.run_transcription(TEMP_AUDIO)
        if os.path.exists(TEMP_AUDIO): os.remove(TEMP_AUDIO)

    def audio_silent(self):
        self.status_label.config(text=T['status_no_audio'], fg="red")
        self.btn_start.config(state=tk.NORMAL, bg="#569d6b")
        self.progress.stop()

    def load_file_dialog(self):
        path = None
        try:
            cmd = ["zenity", "--file-selection", "--title=" + T['zenity_title'],
                   "--file-filter=" + T['zenity_filter'] + " (mp3 wav m4a flac ogg) | *.mp3 *.wav *.m4a *.flac *.ogg",
                   "--file-filter=All files | *"]
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode == 0: path = result.stdout.strip()
        except FileNotFoundError:
            path = filedialog.askopenfilename(filetypes=[("Audio", "*.mp3 *.wav *.m4a *.flac *.ogg"), ("All files", "*.*")])
        if path and os.path.exists(path):
            self.status_label.config(text=T['status_processing'], fg="#2980b9")
            self.progress.start(10)
            threading.Thread(target=self.run_transcription, args=(path,), daemon=True).start()

    def run_transcription(self, path):
        try:
            lang = self.selected_lang.get()
            v = self.beam_slider.get()
            b_size = v if v <= 3 else (5 if v == 4 else 10)
            patience = 1.0 if v <= 3 else 2.0
            segments, _ = self.model.transcribe(path, language=lang, beam_size=b_size, patience=patience, condition_on_previous_text=False, initial_prompt="Transcription.")
            text = " ".join([s.text for s in segments]).strip()
            self.root.after(0, lambda: self.update_ui_post(text))
        except Exception as e:
            self.root.after(0, lambda: self.error_transc(e))

    def update_ui_post(self, text):
        if text:
            prefix = "\n\n" if self.text_area.get(1.0, tk.END).strip() else ""
            self.text_area.insert(tk.END, prefix + text)
            self.text_area.see(tk.END)
            self.root.clipboard_clear()
            self.root.clipboard_append(text)
            self.status_label.config(text=T['status_copied'], fg="#27ae60")
        else:
            self.status_label.config(text=T['status_no_text'], fg="#d35400")
        self.progress.stop()
        self.progress['value'] = 100
        self.btn_start.config(state=tk.NORMAL, bg="#569d6b")
        self.btn_load.config(state=tk.NORMAL)

    def error_transc(self, e):
        self.status_label.config(text=T['status_error'], fg="red")
        self.progress.stop()
        messagebox.showerror("AI Error", str(e))

if __name__ == "__main__":
    root = tk.Tk()
    app = FussListenGUI(root)
    root.mainloop()
