#!/usr/bin/env python3
import os
import sys
import json
from pathlib import Path

# Gibt das Verzeichnis zurück, in dem dieses Skript liegt
def script_dir():
    return Path(__file__).parent.resolve()

# Lädt die JSONC-Konfiguration (Kommentare via // werden ignoriert)
def load_config(filename="config.jsonc"):
    config_path = script_dir() / filename
    if not config_path.exists():
        print(" ⚠  Konfigurationsdatei nicht gefunden:", config_path)
        sys.exit(1)
    with open(config_path, encoding="utf-8") as f:
        # Entfernt //-Kommentare vor dem Parsen
        return json.loads("".join(line for line in f if not line.strip().startswith("//")))

# Parsen der Kommandozeilenargumente
def parse_args():
    args = sys.argv[1:]
    parsed = {
        "scan": None,     # Verzeichnisse zum Scannen (List[str])
        "ignore": [],     # Verzeichnisse, die ignoriert werden sollen (List[str])
        "reset": False,   # Setzt das Logfile zurück
        "hilfe": False,   # Zeigt die Hilfe an
    }

    # Argumente durchgehen und zuweisen
    while args:
        arg = args.pop(0)
        if arg in ("-h", "--hilfe"):
            parsed["hilfe"] = True
        elif arg == "--reset":
            parsed["reset"] = True
        elif arg in ("-s", "--scan") and args:
            parsed["scan"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
        elif arg in ("-x", "--ignore") and args:
            parsed["ignore"] = [entry.strip() for entry in args.pop(0).split(",") if entry.strip()]
        else:
            print(f" ⚠  Unbekannter Parameter: {arg}")
            parsed["hilfe"] = True
            break

    return parsed

# Ausgabe der Hilfetexte für CLI-Nutzer
def show_help():
    print("""
(C) 2025 - Adam Skotarczak (ionivation.com)

🛈 Tool das Verzeichnisse nach Markdown-Dateien durchsucht und diese an eine definierte Liste anhängt als Markdown-Link.
Verwendung: python3 link_collector.py [OPTIONEN]

  -s, --scan    Kommagetrennte Liste von Verzeichnissen zum Durchsuchen (relativ zum Aufrufpfad)
  -x, --ignore  Kommagetrennte Liste von Verzeichnissen, die ignoriert werden sollen
  --reset       Löscht das Logfile 'processed.log' und beendet sich
  -h, --hilfe   Zeigt diese Hilfe

Beispiel:
  python3 link_collector.py -s docs,notes -x "docs/alt"
""")

# Generator: Findet Markdown-Dateien (rekursiv), ignoriert dabei definierte Pfade
def find_md_files(root_dirs, ignore_dirs, extensions):
    for root in root_dirs:
        for dirpath, _, filenames in os.walk(root):
            # Ignorierpfade überspringen
            if any(str(Path(dirpath)).startswith(str(ignored)) for ignored in ignore_dirs):
                continue
            for fname in filenames:
                if any(fname.endswith(ext) for ext in extensions):
                    yield Path(dirpath) / fname

# Extrahiert den ersten Markdown-Titel (# ...) als Linktext
def extract_title(filepath):
    try:
        with open(filepath, encoding="utf-8") as f:
            for line in f:
                if line.strip().startswith("#"):
                    return line.strip("# ").strip()
    except Exception as e:
        print(f"⚠ Fehler beim Lesen von {filepath}: {e}")
    # Fallback: Dateiname ohne Endung
    return filepath.stem

# Liest bereits verarbeitete Dateien aus dem Log (Pfadangaben im POSIX-Format)
def load_processed(logfile):
    if not logfile.exists():
        return set()
    with open(logfile, encoding="utf-8") as f:
        # Vereinheitlichung auf POSIX-Konvention
        return set(Path(line.strip()).as_posix() for line in f)

# Hängt neue Markdown-Links ans Output-Dokument an
def append_to_output(output_path, links):
    with open(output_path, "a", encoding="utf-8") as f:
        for line in links:
            f.write(line + "\n")

# Ergänzt das Logfile um neu verarbeitete Dateien (POSIX-Format)
def update_processed(log_path, new_paths):
    with open(log_path, "a", encoding="utf-8") as f:
        for path in new_paths:
            f.write(path.as_posix() + "\n")

# Hauptfunktion mit gesamtem Ablauf
def main():
    config = load_config()
    args = parse_args()

    if args["hilfe"]:
        show_help()
        return

    log_path = script_dir() / config.get("processed_log", "processed.log")

    # Optionaler Reset des Logs
    if args["reset"]:
        if log_path.exists():
            log_path.unlink()
            print("🧹  Logfile gelöscht:", log_path)
        else:
            print("ℹ Logfile existierte nicht:", log_path)
        return

    cwd = Path.cwd()
    output_file = cwd / config.get("output_file", "output.md")

    # Verzeichnisse aus CLI oder Konfiguration
    root_dirs = args["scan"] or config.get("root_dirs", [])
    root_dirs = [Path(d).resolve() for d in root_dirs if d.strip()]
    ignore_dirs = [Path(x).resolve() for x in args["ignore"]]

    extensions = config.get("extensions", [".md"])
    processed = load_processed(log_path)

    new_links = []
    new_processed = []

    # Dateien durchsuchen und neue Markdown-Dateien verlinken
    for md_file in find_md_files(root_dirs, ignore_dirs, extensions):
        if md_file.resolve() == output_file.resolve():
            continue  # nicht sich selbst verlinken
        rel_path = md_file.relative_to(cwd)
        rel_path_posix = rel_path.as_posix()
        if rel_path_posix in processed:
            continue  # bereits im Logfile
        title = extract_title(md_file)
        new_links.append(f"- [{title}]({rel_path_posix})")
        new_processed.append(rel_path)

    # Ergebnisse schreiben
    if new_links:
        append_to_output(output_file, new_links)
        update_processed(log_path, new_processed)
        print(f"✔ {len(new_links)} neue Links hinzugefügt.")
    else:
        print(" ℹ  Keine neuen Dateien gefunden.")

if __name__ == "__main__":
    main()
