import os
import argostranslate.package
import argostranslate.translate
import torch
from tkinter import filedialog, Tk
from multiprocessing import Pool, cpu_count
from tqdm import tqdm
import pdfplumber
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

def setup_translation(from_code, to_code):
    """Configurează pachetul de traducere pentru limbile selectate"""
    try:
        print("Actualizare index pachete...")
        argostranslate.package.update_package_index()
        available_packages = argostranslate.package.get_available_packages()
        package_to_install = next(
            filter(
                lambda x: x.from_code == from_code and x.to_code == to_code, 
                available_packages
            ), None
        )
        if not package_to_install:
            print(f"Nu există pachet de traducere disponibil pentru {from_code} -> {to_code}")
            return False
        
        print(f"Descărcare pachet de traducere {from_code} -> {to_code}...")
        argostranslate.package.install_from_path(package_to_install.download())
        return True
    except Exception as e:
        print(f"Eroare la configurare: {str(e)}")
        return False

def select_device():
    """Detectează și selectează dispozitivul (NPU -> GPU -> CPU)"""
    device = None
    device_name = None
    
    try:
        if hasattr(torch, 'npu') and torch.npu.is_available():
            device = torch.device("npu")
            device_name = "NPU"
            print("NPU detectat, voi folosi NPU pentru traducere.")
    except AttributeError:
        pass
    
    if device is None and torch.cuda.is_available():
        device = torch.device("cuda")
        device_name = "GPU"
        print("GPU detectat, voi folosi GPU pentru traducere.")
    
    if device is None:
        device = torch.device("cpu")
        device_name = "CPU"
        print("Niciun NPU sau GPU detectat, voi folosi CPU pentru traducere.")
    
    return device, device_name

def choose_language():
    """Permite utilizatorului să aleagă limbile de traducere"""
    print("Vrei să folosești traducerea implicită EN -> RO? (da/nu)")
    choice = input().strip().lower()
    
    if choice in ["da", "d", "yes", "y"]:
        return "en", "ro"
    
    if choice not in ["nu", "n", "no"]:
        print("Răspuns invalid. Folosesc implicit EN -> RO.")
        return "en", "ro"
    
    languages = [
        ("en", "Engleză"),
        ("es", "Spaniolă"),
        ("fr", "Franceză"),
        ("de", "Germană"),
        ("zh", "Chineză"),
        ("ru", "Rusă"),
        ("ar", "Arabă"),
        ("ro", "Română")
    ]
    
    print("\nSelectează limba sursă (introduce numărul):")
    for i, (code, name) in enumerate(languages, 1):
        print(f"{i}. {name} ({code})")
    
    try:
        from_idx = int(input()) - 1
        if not 0 <= from_idx < len(languages):
            raise ValueError
        from_code = languages[from_idx][0]
    except (ValueError, IndexError):
        print("Selecție invalidă. Folosesc implicit Engleză (en).")
        from_code = "en"
    
    print("\nSelectează limba destinație (introduce numărul):")
    for i, (code, name) in enumerate(languages, 1):
        print(f"{i}. {name} ({code})")
    
    try:
        to_idx = int(input()) - 1
        if not 0 <= to_idx < len(languages) or to_idx == from_idx:
            raise ValueError
        to_code = languages[to_idx][0]
    except (ValueError, IndexError):
        print("Selecție invalidă. Folosesc implicit Română (ro).")
        to_code = "ro"
    
    return from_code, to_code

def extract_text_lines_with_position(pdf_path):
    """Extrage textul pe linii cu poziționarea lor"""
    text_data = []
    try:
        with pdfplumber.open(pdf_path) as pdf:
            for page_num, page in enumerate(pdf.pages, 1):
                # Extragem textul pe linii folosind extract_text_lines
                lines = page.extract_text_lines()
                for line in lines:
                    text_data.append({
                        'text': line['text'],
                        'x0': line['x0'],
                        'top': line['top'],
                        'page': page_num,
                        'width': page.width,
                        'height': page.height,
                        'x1': line['x1']  # Pentru a calcula lungimea liniei
                    })
        return text_data
    except Exception as e:
        print(f"Eroare la extragerea textului cu poziție: {str(e)}")
        return None

def text_to_pdf(text_data, translated_texts, output_path, page_sizes):
    """Convertește textul tradus în PDF păstrând așezarea în pagină"""
    try:
        # Încărcăm fontul DejaVuSans pentru suport diacritice
        pdfmetrics.registerFont(TTFont('DejaVuSans', 'DejaVuSans.ttf'))
        c = canvas.Canvas(output_path, pagesize=letter)
        
        current_page = 1
        for i, item in enumerate(text_data):
            if item['page'] != current_page:
                c.showPage()
                current_page = item['page']
                c.setPageSize((item['width'], item['height']))
            
            c.setFont('DejaVuSans', 12)
            y_pos = item['height'] - item['top']
            
            # Ajustăm textul tradus pentru a se potrivi spațiului original
            original_width = item['x1'] - item['x0']
            translated_text = translated_texts[i]
            
            # Calculăm lățimea textului tradus
            text_width = c.stringWidth(translated_text, 'DejaVuSans', 12)
            
            # Dacă textul tradus e prea lung, reducem dimensiunea fontului
            if text_width > original_width:
                font_size = 12 * (original_width / text_width)
                font_size = max(font_size, 6)  # Limităm reducerea la 6pt
                c.setFont('DejaVuSans', font_size)
            
            c.drawString(item['x0'], y_pos, translated_text)
        
        c.save()
    except Exception as e:
        print(f"Eroare la crearea PDF-ului: {str(e)}")

def translate_file(args):
    """Funcție pentru traducerea unui singur fișier PDF cu bară de progres"""
    file_path, from_code, to_code, output_dir, device_name = args
    file_name = os.path.basename(file_path)
    
    try:
        print(f"Procesez: {file_name} cu {device_name}")
        
        # Extragem textul pe linii cu poziționarea
        text_data = extract_text_lines_with_position(file_path)
        if not text_data:
            return
        
        # Pregătim textul pentru traducere
        original_texts = [item['text'] for item in text_data]
        translated_texts = []
        
        # Împărțim în bucăți pentru progres
        text_chunks = [original_texts[i:i+10] for i in range(0, len(original_texts), 10)]
        
        with tqdm(total=len(text_chunks), desc=f"Traduc {file_name}", leave=False) as pbar:
            for chunk in text_chunks:
                translated_chunk = [argostranslate.translate.translate(text, from_code, to_code) for text in chunk]
                translated_texts.extend(translated_chunk)
                pbar.update(1)
        
        # Generăm noul nume de fișier
        output_file_name = f"{os.path.splitext(file_name)[0]}_translated.pdf"
        output_path = os.path.join(output_dir, output_file_name)
        
        # Obținem dimensiunile paginilor
        with pdfplumber.open(file_path) as pdf:
            page_sizes = [(page.width, page.height) for page in pdf.pages]
        
        # Convertim textul tradus înapoi în PDF
        text_to_pdf(text_data, translated_texts, output_path, page_sizes)
        
        print(f"Complet: {output_file_name}")
    except Exception as e:
        print(f"Eroare la {file_name}: {str(e)}")

def translate_files():
    """Traduce fișierele PDF selectate în paralel"""
    # Alegere limbi
    from_code, to_code = choose_language()
    print(f"\nTraducere selectată: {from_code} -> {to_code}")
    
    # Configurare traducere
    if not setup_translation(from_code, to_code):
        return
    
    # Detectare dispozitiv
    device, device_name = select_device()
    
    # Selectare fișiere
    root = Tk()
    root.withdraw()
    files = filedialog.askopenfilenames(
        title="Selectează fișierele PDF de tradus",
        filetypes=[("PDF files", "*.pdf")]
    )
    root.destroy()
    
    if not files:
        print("Niciun fișier selectat. Program terminat.")
        return
    
    # Creare folder output
    script_dir = os.path.dirname(os.path.abspath(__file__))
    output_dir = os.path.join(script_dir, to_code)
    os.makedirs(output_dir, exist_ok=True)
    
    # Număr de procesoare disponibile
    num_processes = cpu_count()
    print(f"\nDetectate {num_processes} nuclee CPU. Procesez {len(files)} fișiere în paralel folosind {device_name}...")
    
    # Pregătire argumente pentru procesare paralelă
    tasks = [(file_path, from_code, to_code, output_dir, device_name) for file_path in files if file_path.endswith('.pdf')]
    
    # Procesare paralelă
    with Pool(processes=num_processes) as pool:
        pool.map(translate_file, tasks)
    
    print(f"\nTraducere completă! Fișierele sunt în folderul '{to_code}'.")

if __name__ == "__main__":
    translate_files()
