import tkinter as tk
from tkinter import scrolledtext, filedialog, messagebox, ttk
import os
import threading
import subprocess
import time
import sys
from TTS.api import TTS

class RomanianTTSApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Text-to-Speech pentru Limba Română")
        self.root.geometry("700x550")
        
        # Inițializare TTS
        self.model_name = "tts_models/ro/cv/vits"
        self.tts = None
        self.initialize_tts()
        
        # Director pentru fișiere audio
        self.output_dir = "output_audio"
        if not os.path.exists(self.output_dir):
            os.makedirs(self.output_dir)
        
        # Creare interfață
        self.create_widgets()
    
    def initialize_tts(self):
        try:
            self.status_message = "Se inițializează modelul TTS..."
            self.tts = TTS(model_name=self.model_name)
            self.model_initialized = True
        except Exception as e:
            self.model_initialized = False
            self.status_message = f"Eroare la inițializarea modelului: {e}"
            print(self.status_message)
    
    def create_widgets(self):
        # Stilizare
        bg_color = "#f5f5f5"
        button_bg = "#4CAF50"
        button_fg = "white"
        button_font = ("Arial", 10, "bold")
        
        # Cadrul principal
        main_frame = tk.Frame(self.root, padx=15, pady=15, bg=bg_color)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # Titlu
        title_label = tk.Label(main_frame, 
                              text="Text-to-Speech pentru Limba Română", 
                              font=("Arial", 14, "bold"),
                              bg=bg_color)
        title_label.pack(pady=(0, 15))
        
        # Cadru pentru butoane de încărcare text
        load_frame = tk.Frame(main_frame, bg=bg_color)
        load_frame.pack(fill=tk.X, pady=(0, 10))
        
        # Etichetă pentru instrucțiuni
        instructions = tk.Label(load_frame, 
                               text="Introduceți textul sau încărcați din fișier:",
                               font=("Arial", 10),
                               bg=bg_color)
        instructions.pack(side=tk.LEFT, anchor=tk.W)
        
        # Buton pentru încărcare fișier text
        self.load_button = tk.Button(load_frame, text="Încarcă fișier text", 
                                     command=self.load_text_file,
                                     bg="#2196F3", fg=button_fg, 
                                     font=button_font)
        self.load_button.pack(side=tk.RIGHT)
        
        # Zona de text
        self.text_area = scrolledtext.ScrolledText(main_frame, 
                                                   wrap=tk.WORD, 
                                                   font=("Arial", 11),
                                                   height=12)
        self.text_area.pack(fill=tk.BOTH, expand=True, pady=(0, 15))
        self.text_area.insert(tk.END, "Acesta este un test pentru sistemul text-to-speech în limba română.")
        
        # Cadru pentru opțiuni
        options_frame = tk.Frame(main_frame, bg=bg_color)
        options_frame.pack(fill=tk.X, pady=(0, 10))
        
        # Opțiune pentru procesare pe segmente 
        self.chunk_var = tk.BooleanVar(value=True)
        chunk_check = tk.Checkbutton(options_frame, 
                                     text="Procesare pe segmente (recomandat pentru texte mari)", 
                                     variable=self.chunk_var,
                                     bg=bg_color)
        chunk_check.pack(side=tk.LEFT)
        
        # Cadru pentru progres
        progress_frame = tk.Frame(main_frame, bg=bg_color)
        progress_frame.pack(fill=tk.X, pady=(0, 10))
        
        # Bară de progres
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(progress_frame, 
                                           variable=self.progress_var,
                                           mode="determinate",
                                           length=100)
        self.progress_bar.pack(fill=tk.X, pady=(0, 5))
        
        # Etichetă pentru progres
        self.progress_text = tk.StringVar(value="Gata pentru conversie")
        progress_label = tk.Label(progress_frame, 
                                 textvariable=self.progress_text,
                                 bg=bg_color)
        progress_label.pack(anchor=tk.W)
        
        # Cadru pentru butoane principale
        buttons_frame = tk.Frame(main_frame, bg=bg_color)
        buttons_frame.pack(fill=tk.X, pady=(5, 15))
        
        # Buton pentru generare și redare
        self.play_button = tk.Button(buttons_frame, text="Generează și redă", 
                                     command=self.generate_and_play, 
                                     width=18, height=2,
                                     bg=button_bg, fg=button_fg, 
                                     font=button_font)
        self.play_button.pack(side=tk.LEFT, padx=(0, 15))
        
        # Buton pentru salvare
        self.save_button = tk.Button(buttons_frame, text="Salvare fișier audio", 
                                     command=self.save_speech, 
                                     width=18, height=2,
                                     bg="#2196F3", fg=button_fg, 
                                     font=button_font)
        self.save_button.pack(side=tk.LEFT)
        
        # Buton pentru anulare conversie
        self.cancel_button = tk.Button(buttons_frame, text="Anulează", 
                                      command=self.cancel_conversion, 
                                      width=12, height=2,
                                      bg="#f44336", fg=button_fg, 
                                      font=button_font,
                                      state=tk.DISABLED)
        self.cancel_button.pack(side=tk.RIGHT)
        
        # Informații despre status
        self.status_var = tk.StringVar(value="Gata pentru conversie")
        status_label = tk.Label(main_frame, textvariable=self.status_var,
                               font=("Arial", 9, "italic"),
                               bg=bg_color)
        status_label.pack(anchor=tk.W, pady=(10, 0))
        
        # Variabile pentru procesare
        self.is_processing = False
        self.cancel_requested = False
    
    def load_text_file(self):
        """Încarcă text dintr-un fișier"""
        file_path = filedialog.askopenfilename(
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
        )
        
        if not file_path:
            return
        
        try:
            self.status_var.set(f"Se încarcă fișierul: {os.path.basename(file_path)}")
            self.root.update()
            
            # Determinăm codificarea fișierului
            encodings = ['utf-8', 'iso-8859-1', 'latin-1', 'cp1252']
            content = None
            
            for encoding in encodings:
                try:
                    with open(file_path, 'r', encoding=encoding) as file:
                        content = file.read()
                    break
                except UnicodeDecodeError:
                    continue
            
            if content is None:
                # Încercare ultimă cu detectare de encoding
                try:
                    import chardet
                    with open(file_path, 'rb') as file:
                        raw_data = file.read()
                    detected = chardet.detect(raw_data)
                    encoding = detected['encoding']
                    with open(file_path, 'r', encoding=encoding) as file:
                        content = file.read()
                except (ImportError, Exception) as e:
                    raise Exception(f"Nu s-a putut determina codificarea fișierului: {e}")
            
            # Actualizăm zona de text
            self.text_area.delete("1.0", tk.END)
            self.text_area.insert(tk.END, content)
            
            file_size = os.path.getsize(file_path) / 1024  # KB
            self.status_var.set(f"Fișier încărcat: {os.path.basename(file_path)} ({file_size:.1f} KB)")
        except Exception as e:
            self.status_var.set(f"Eroare la încărcarea fișierului: {e}")
            messagebox.showerror("Eroare", f"Nu s-a putut încărca fișierul:\n{str(e)}")
    
    def generate_and_play(self):
        """Generează audio și redă"""
        if self.is_processing:
            return
        
        text = self.text_area.get("1.0", tk.END).strip()
        if not text:
            messagebox.showwarning("Avertisment", "Introduceți text pentru conversie!")
            return
        
        self.is_processing = True
        self.cancel_requested = False
        
        self.status_var.set("Se pregătește procesarea...")
        self.progress_var.set(0)
        self.progress_text.set("Pregătire...")
        
        self.play_button.config(state=tk.DISABLED)
        self.save_button.config(state=tk.DISABLED)
        self.load_button.config(state=tk.DISABLED)
        self.cancel_button.config(state=tk.NORMAL)
        
        self.root.update()
        
        # Procesăm într-un thread separat
        self.process_thread = threading.Thread(
            target=self.process_text_to_speech,
            args=(text, os.path.join(self.output_dir, "temp_speech.wav"), True)
        )
        self.process_thread.start()
    
    def save_speech(self):
        """Salvează text în fișier audio"""
        if self.is_processing:
            return
        
        text = self.text_area.get("1.0", tk.END).strip()
        if not text:
            messagebox.showwarning("Avertisment", "Introduceți text pentru conversie!")
            return
        
        file_path = filedialog.asksaveasfilename(
            defaultextension=".wav",
            filetypes=[("WAV files", "*.wav"), ("All files", "*.*")]
        )
        
        if not file_path:
            return
        
        self.is_processing = True
        self.cancel_requested = False
        
        self.status_var.set("Se pregătește procesarea...")
        self.progress_var.set(0)
        self.progress_text.set("Pregătire...")
        
        self.play_button.config(state=tk.DISABLED)
        self.save_button.config(state=tk.DISABLED)
        self.load_button.config(state=tk.DISABLED)
        self.cancel_button.config(state=tk.NORMAL)
        
        self.root.update()
        
        # Procesăm într-un thread separat
        self.process_thread = threading.Thread(
            target=self.process_text_to_speech,
            args=(text, file_path, False)
        )
        self.process_thread.start()
    
    def cancel_conversion(self):
        """Anulează procesarea în curs"""
        if self.is_processing:
            self.cancel_requested = True
            self.status_var.set("Se anulează procesarea...")
            self.progress_text.set("Anulare în curs...")
            self.root.update()
    
    def process_text_to_speech(self, text, output_file, play_after=False):
        """Procesează textul pentru conversie TTS cu monitorizare progres"""
        try:
            # Verificăm dacă procesăm pe segmente sau tot textul deodată
            if self.chunk_var.get() and len(text) > 500:
                # Împărțim textul în propoziții sau paragrafe
                segments = self.split_text(text)
                total_segments = len(segments)
                
                # Pregătim fișierele temporare pentru segmente
                temp_files = []
                for i, segment in enumerate(segments):
                    if self.cancel_requested:
                        break
                    
                    # Actualizăm progresul
                    progress = (i / total_segments) * 100
                    self.update_progress(progress, 
                                         f"Se procesează segmentul {i+1}/{total_segments}...")
                    
                    # Generăm audio pentru segment
                    segment_text = segment.strip()
                    if segment_text:
                        temp_file = os.path.join(self.output_dir, f"temp_segment_{i}.wav")
                        self.tts.tts_to_file(text=segment_text, file_path=temp_file)
                        temp_files.append(temp_file)
                
                if not self.cancel_requested and temp_files:
                    # Combinăm segmentele
                    self.update_progress(95, "Se combină segmentele audio...")
                    self.combine_audio_files(temp_files, output_file)
                    
                    # Ștergem fișierele temporare
                    for temp_file in temp_files:
                        try:
                            os.remove(temp_file)
                        except:
                            pass
            else:
                # Procesăm tot textul deodată
                self.update_progress(10, "Se inițializează procesarea...")
                self.tts.tts_to_file(text=text, file_path=output_file)
                self.update_progress(90, "Finalizare procesare...")
            
            # Finalizare
            if self.cancel_requested:
                self.update_progress(100, "Procesare anulată")
                self.status_var.set("Procesare anulată")
            else:
                self.update_progress(100, "Procesare finalizată")
                self.status_var.set(f"Fișier audio generat: {os.path.basename(output_file)}")
                
                # Redăm dacă este cazul
                if play_after and not self.cancel_requested:
                    self.update_progress(100, "Se redă audio...")
                    self.play_audio(output_file)
                    self.status_var.set("Redare finalizată")
        
        except Exception as e:
            self.update_progress(0, "Eroare")
            error_msg = str(e)
            self.status_var.set(f"Eroare: {error_msg[:50]}..." if len(error_msg) > 50 else f"Eroare: {error_msg}")
            messagebox.showerror("Eroare", str(e))
        
        finally:
            # Resetăm interfața
            self.play_button.config(state=tk.NORMAL)
            self.save_button.config(state=tk.NORMAL)
            self.load_button.config(state=tk.NORMAL)
            self.cancel_button.config(state=tk.DISABLED)
            self.is_processing = False
            self.cancel_requested = False
    
    def update_progress(self, value, message):
        """Actualizează bara de progres și mesajul"""
        if self.root.winfo_exists():
            self.progress_var.set(value)
            self.progress_text.set(message)
            self.root.update()
    
    def split_text(self, text):
        """Împarte textul în segmente mai mici pentru procesare"""
        # Mai întâi împărțim după punctuație completă (. ? !)
        import re
        sentences = re.split(r'(?<=[.!?])\s+', text)
        
        # Acum grupăm propozițiile în segmente de lungime rezonabilă (max ~500 caractere)
        segments = []
        current_segment = ""
        
        for sentence in sentences:
            if len(current_segment) + len(sentence) > 500:
                if current_segment:
                    segments.append(current_segment)
                current_segment = sentence
            else:
                if current_segment:
                    current_segment += " " + sentence
                else:
                    current_segment = sentence
        
        if current_segment:
            segments.append(current_segment)
        
        # Dacă segmentele sunt prea puține, le împărțim și mai mult
        if len(segments) < 3 and len(text) > 1500:
            new_segments = []
            for segment in segments:
                if len(segment) > 500:
                    # Împărțim după virgulă sau punct și virgulă
                    parts = re.split(r'(?<=,|;)\s+', segment)
                    
                    temp_segment = ""
                    for part in parts:
                        if len(temp_segment) + len(part) > 500:
                            if temp_segment:
                                new_segments.append(temp_segment)
                            temp_segment = part
                        else:
                            if temp_segment:
                                temp_segment += " " + part
                            else:
                                temp_segment = part
                    
                    if temp_segment:
                        new_segments.append(temp_segment)
                else:
                    new_segments.append(segment)
            
            segments = new_segments
        
        return segments
    
    def combine_audio_files(self, input_files, output_file):
        """Combină mai multe fișiere audio wav într-unul singur"""
        try:
            import wave
            import array
            
            data = []
            for input_file in input_files:
                w = wave.open(input_file, 'rb')
                data.append([w.getparams(), w.readframes(w.getnframes())])
                w.close()
            
            output = wave.open(output_file, 'wb')
            output.setparams(data[0][0])
            
            # Scriem datele audio din toate fișierele
            for i in range(len(data)):
                output.writeframes(data[i][1])
            
            output.close()
            
        except ImportError:
            # Dacă nu avem acces la wave, vom folosi un alt fișier
            raise Exception("Nu s-a putut importa modulul wave pentru concatenarea fișierelor audio.")
    
    def play_audio(self, file_path):
        """Redă fișierul audio folosind player-ul implicit"""
        try:
            if os.name == 'nt':  # Windows
                os.startfile(file_path)
            elif os.name == 'posix':  # macOS și Linux
                subprocess.call(('open' if sys.platform == 'darwin' else 'xdg-open', file_path))
        except Exception as e:
            print(f"Eroare la redarea audio: {e}")

# Rulare aplicație
if __name__ == "__main__":
    root = tk.Tk()
    app = RomanianTTSApp(root)
    root.mainloop()
