#!/usr/bin/env python3
import sys
print("▶▶▶ START Querverweise.py", file=sys.stderr)

import fitz  # PyMuPDF
print("   ✔ fitz importiert", file=sys.stderr)
import re
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
print("   ✔ tkinter importiert", file=sys.stderr)

# Globale Einstellungen
current_language = "de"   # Standard: Deutsch
create_logfile = False    # Standard: Logfile aus

# Übersetzungstexte
texts = {
    "de": {
        "window_title": "QElectroTech - Querverweis-Analyse",
        "pdf_select": "PDF-Datei auswählen:",
        "browse": "Durchsuchen",
        "scan_tab": "Querverweise scannen",
        "settings_tab": "Einstellungen",
        "format_label": "Querverweis-Format:",
        "x_x": "X.X",
        "x_x_x": "X.X.X",
        "scan_start": "Scan starten",
        "exit": "Beenden",
        "pdf_success": "PDF {filepath} erfolgreich geöffnet. Seiten: {pages}",
        "log_pdf_selected": "PDF-Datei ausgewählt: {filepath}",
        "error_no_pdf": "Bitte PDF-Datei angeben.",
        "error": "Fehler",
        "success_pdf_saved": "PDF mit Verlinkung gespeichert: {save_pdf_path}",
        "success_results_saved": "Ergebnisse gespeichert: {save_txt_path}",
        "success": "Erfolg",
        "pdf_scan_saved": "PDF und Scan-Ergebnisse gespeichert!",
        "found_refs": "Gefundene Querverweise: {count}",
        "log_link": "Link: {ref} auf Seite {page} → Zielseite {target_page}",
        "error_creating_link": "Fehler beim Erstellen des Links für {ref} auf Seite {page}: {error}",
        "error_extraction": "Fehler beim Extrahieren des Zielwerts aus {ref}: {error}",
        "language": "Sprache",
        "logfile": "Logfile erstellen?",
        "yes": "Ja",
        "no": "Nein"
    },
    "en": {
        "window_title": "QElectroTech - Cross-Reference Analysis",
        "pdf_select": "Select PDF File:",
        "browse": "Browse",
        "scan_tab": "Scan Cross-References",
        "settings_tab": "Settings",
        "format_label": "Reference Format:",
        "x_x": "X.X",
        "x_x_x": "X.X.X",
        "scan_start": "Start Scan",
        "exit": "Exit",
        "pdf_success": "PDF {filepath} opened successfully. Pages: {pages}",
        "log_pdf_selected": "PDF file selected: {filepath}",
        "error_no_pdf": "Please specify a PDF file.",
        "error": "Error",
        "success_pdf_saved": "PDF with links saved: {save_pdf_path}",
        "success_results_saved": "Results saved: {save_txt_path}",
        "success": "Success",
        "pdf_scan_saved": "PDF and scan results saved!",
        "found_refs": "Found cross-references: {count}",
        "log_link": "Link: {ref} on page {page} → Target page {target_page}",
        "error_creating_link": "Error creating link for {ref} on page {page}: {error}",
        "error_extraction": "Error extracting target from {ref}: {error}",
        "language": "Language",
        "logfile": "Create logfile?",
        "yes": "Yes",
        "no": "No"
    }
}

# Neue globale Variablen für Skip-Range
skip_enabled = False
skip_from = None
skip_to = None

# Regex zum Extrahieren der Seitenzahl im PDF
page_num_pattern = re.compile(r"Seite[:\s]*(\d{1,3})", re.IGNORECASE)

# ------------------------------
# Funktionen
# ------------------------------
def log_message(message):
    text_log.insert(tk.END, message + "\n")
    text_log.yview(tk.END)
    print(message, file=sys.stderr)


def is_date(candidate):
    return re.fullmatch(r"(0?[1-9]|[12]\d|3[01])\.(0?[1-9]|1[0-2])\.(\d{2}|\d{4})", candidate) is not None


def extract_page_mapping(doc):
    """
    Durchsucht jede Seite im PDF nach dem Text 'Seite: X' in der unteren Ecke
    und erstellt ein Mapping {plan_seite: pdf_page_index}.
    """
    mapping = {}
    for idx in range(len(doc)):
        page = doc.load_page(idx)
        text = page.get_text("text")
        match = page_num_pattern.search(text)
        if match:
            plan_num = int(match.group(1))
            mapping[plan_num] = idx
    return mapping


def scan_and_link_pdf():
    global skip_from, skip_to

    # Skip-Range auslesen
    skip = var_skip.get()
    if skip:
        try:
            sf = int(entry_from.get())
            st = int(entry_to.get())
            if sf < 1 or st < sf:
                raise ValueError("Bereich ungültig")
            skip_from, skip_to = sf, st
        except Exception as e:
            messagebox.showerror(texts[current_language]["error"], f"Ungültiger Seitenbereich: {e}")
            return
    else:
        skip_from = skip_to = None

    pdf_path = entry_pdf_path.get()
    ref_pattern = r"\b\d{1,3}\.\d{1,3}(?:\.\d{1,3})?\b"

    if not pdf_path:
        messagebox.showerror(texts[current_language]["error"], texts[current_language]["error_no_pdf"])
        log_message(texts[current_language]["error_no_pdf"])
        return

    try:
        doc = fitz.open(pdf_path)
        total_pages = len(doc)
        log_message(texts[current_language]["pdf_success"].format(filepath=pdf_path, pages=total_pages))

        # 1. Mapping extrahieren
        page_mapping = extract_page_mapping(doc)
        if not page_mapping:
            log_message("Warnung: Keine Seitenzahlen im PDF gefunden. Mapping unvollständig.")

        results = []

        # 2. Querverweise suchen und verlinken
        for page_num in range(total_pages):
            if skip and skip_from <= page_num+1 <= skip_to:
                continue
            page = doc.load_page(page_num)
            text_dict = page.get_text("dict")
            for block in text_dict.get("blocks", []):
                if block.get("type") != 0:
                    continue
                for line in block.get("lines", []):
                    for span in line.get("spans", []):
                        span_text = span.get("text", "")
                        for match in re.finditer(ref_pattern, span_text):
                            ref_full = match.group(0).strip()
                            if is_date(ref_full):
                                continue
                            results.append((ref_full, page_num + 1))
                            try:
                                plan_page = int(ref_full.split('.')[0])
                                target_idx = page_mapping[plan_page]
                            except Exception as ex:
                                log_message(texts[current_language]["error_extraction"].format(ref=ref_full, error=ex))
                                continue
                            try:
                                rect = fitz.Rect(span["bbox"])
                                page.insert_link({"kind": fitz.LINK_GOTO, "page": target_idx, "from": rect})
                                log_message(texts[current_language]["log_link"].format(ref=ref_full, page=page_num+1, target_page=target_idx+1))
                            except Exception as e:
                                log_message(texts[current_language]["error_creating_link"].format(ref=ref_full, page=page_num+1, error=e))

        log_message(texts[current_language]["found_refs"].format(count=len(results)))

        # Logfile erstellen
        if create_logfile:
            save_txt_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])
            if save_txt_path:
                with open(save_txt_path, "w", encoding="utf-8") as file:
                    for ref, page in results:
                        file.write(f"Querverweis {ref} auf Seite {page}\n")
                log_message(texts[current_language]["success_results_saved"].format(save_txt_path=save_txt_path))

        # PDF speichern
        save_pdf_path = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF Files", "*.pdf")])
        if save_pdf_path:
            doc.save(save_pdf_path)
            log_message(texts[current_language]["success_pdf_saved"].format(save_pdf_path=save_pdf_path))
            messagebox.showinfo(texts[current_language]["success"], texts[current_language]["pdf_scan_saved"])

    except Exception as e:
        messagebox.showerror(texts[current_language]["error"], f"{texts[current_language]['error']}: {e}")
        log_message(f"{texts[current_language]['error']}: {e}")

# ------------------------------
# GUI-Aufbau
# ------------------------------
root = tk.Tk()
root.title(texts[current_language]["window_title"])
root.geometry("800x600")

# Oberer Bereich: PDF-Auswahl
frame_top = tk.Frame(root)
frame_top.pack(pady=5, fill=tk.X)
label_pdf_select = tk.Label(frame_top, text=texts[current_language]["pdf_select"])
label_pdf_select.pack(side=tk.LEFT, padx=5)
entry_pdf_path = tk.Entry(frame_top, width=50)
entry_pdf_path.pack(side=tk.LEFT, padx=5)
button_browse = tk.Button(frame_top, text=texts[current_language]["browse"], command=lambda: setattr(entry_pdf_path, 'text', '') or entry_pdf_path.delete(0, tk.END) or filedialog.askopenfilename(filetypes=[("PDF Files", "*.pdf")]) or None)
button_browse.config(command=lambda: (entry_pdf_path.delete(0, tk.END), entry_pdf_path.insert(0, filedialog.askopenfilename(filetypes=[("PDF Files", "*.pdf")])), log_message(texts[current_language]["log_pdf_selected"].format(filepath=entry_pdf_path.get()))))
button_browse.pack(side=tk.LEFT, padx=5)

# Notebook (Tabs)
tab_control = ttk.Notebook(root)
# Tab 1: Querverweise scannen
frame_scan = ttk.Frame(tab_control)
tab_control.add(frame_scan, text=texts[current_language]["scan_tab"])
frame_skip = tk.Frame(frame_scan)
frame_skip.pack(pady=5, fill=tk.X)
var_skip = tk.BooleanVar(value=False)
chk_skip = tk.Checkbutton(frame_skip, text="Seiten überspringen", variable=var_skip, command=lambda: (entry_from.config(state="normal" if var_skip.get() else "disabled"), entry_to.config(state="normal" if var_skip.get() else "disabled")))
chk_skip.pack(side=tk.LEFT, padx=5)
label_from = tk.Label(frame_skip, text="von:")
label_from.pack(side=tk.LEFT, padx=(20,2))
entry_from = tk.Entry(frame_skip, width=5, state="disabled")
entry_from.pack(side=tk.LEFT)
label_to = tk.Label(frame_skip, text="bis:")
label_to.pack(side=tk.LEFT, padx=(10,2))
entry_to = tk.Entry(frame_skip, width=5, state="disabled")
entry_to.pack(side=tk.LEFT)
frame_format = tk.Frame(frame_scan)
frame_format.pack(pady=5)
label_format = tk.Label(frame_format, text=texts[current_language]["format_label"])
label_format.pack(side=tk.LEFT, padx=5)
format_var = tk.StringVar(value="X.X")
radiobutton_xx = tk.Radiobutton(frame_format, text=texts[current_language]["x_x"], variable=format_var, value="X.X")
radiobutton_xx.pack(side=tk.LEFT)
radiobutton_xxx = tk.Radiobutton(frame_format, text=texts[current_language]["x_x_x"], variable=format_var, value="X.X.X")
radiobutton_xxx.pack(side=tk.LEFT)
button_scan = tk.Button(frame_scan, text=texts[current_language]["scan_start"], command=lambda: threading.Thread(target=scan_and_link_pdf, daemon=True).start())
button_scan.pack(pady=5)
text_log = tk.Text(frame_scan, wrap=tk.WORD, height=20)
text_log.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)
# Tab 2: Einstellungen
frame_settings = ttk.Frame(tab_control)
tab_control.add(frame_settings, text=texts[current_language]["settings_tab"])
label_language = tk.Label(frame_settings, text=texts[current_language]["language"])
label_language.pack(pady=5)
combo_language = ttk.Combobox(frame_settings, values=["Deutsch", "English"], state="readonly")
combo_language.current(0)
combo_language.bind("<<ComboboxSelected>>", lambda e: None)
combo_language.pack(pady=5)
label_logfile = tk.Label(frame_settings, text=texts[current_language]["logfile"])
label_logfile.pack(pady=5)
combo_logfile = ttk.Combobox(frame_settings, values=(texts[current_language]["yes"], texts[current_language]["no"]), state="readonly")
combo_logfile.current(1)
combo_logfile.bind("<<ComboboxSelected>>", lambda e: None)
combo_logfile.pack(pady=5)
tab_control.pack(expand=True, fill=tk.BOTH)
button_exit = tk.Button(root, text=texts[current_language]["exit"], command=root.destroy)
button_exit.pack(pady=5)
print("   ✔ Vor root.mainloop()", file=sys.stderr)
root.mainloop()
print("   ✔ Nach root.mainloop() - Programm beendet", file=sys.stderr)

