import re
import os
import pandas as pd
import subprocess
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor


# Datei einlesen
repo_path = r'C:\Users\Kon\Documents\geoserver'
file_path = r'C:\Users\Kon\Documents\geoserver\src\platform\src\main\java\org\geoserver\platform\resource\URIs.java'

try:
    with open(file_path, "r", encoding="utf-8") as f:
        lines = f.readlines()
except FileNotFoundError:
    print(f"Datei nicht gefunden: {file_path}")
    exit()


# Methode zur Erkennung von Methoden und Konstruktoren mit Einrückung
def analyze_methods(lines):
    method_start_end = []
    current_method_start = None
    current_method_signature = None
    indent_level = 4  # Standard Einrückungslevel, um Methoden/Konstruktoren zu erkennen

    for idx, line in enumerate(lines):
        # Leerzeichen zählen
        leading_spaces = len(line) - len(line.lstrip(' '))
        stripped_line = line.strip()
        
        # Methode oder Konstruktor starten erkennen
        if (stripped_line.startswith('public')  or stripped_line.startswith('private') or stripped_line.startswith('protected') or stripped_line.startswith('void') or stripped_line.startswith('static')) and leading_spaces == indent_level:
            current_method_start = idx
            current_method_signature = stripped_line  # Methoden-Signatur erfassen
            print(f"Detected method/konstruktor start at index {idx}: {current_method_signature}")
        
        # Methode oder Konstruktor abschließen erkennen
        if stripped_line == '}' and leading_spaces == indent_level:
            if current_method_start is not None:
                method_start_end.append({
                    "method_signature": current_method_signature,
                    "start_line": current_method_start + 1,  # Konvertieren zu 1-basierten Zeilennummern
                    "end_line": idx + 1
                })
                print(f"Detected method/konstruktor end at index {idx}")
                current_method_start = None
                current_method_signature = None

    # Ergebnisse ausgeben
    print(f"{'Methoden-Signatur':<100}{'Startzeile':<12}{'Endzeile':<12}{'Zeilenanzahl':<8}{'Abstand zur nächsten Methode':<30}")
    print("-" * 100)

    for i, method in enumerate(method_start_end):
        method_size = (method["end_line"] - method["start_line"] + 1)  # Anzahl der Zeilen innerhalb der Methode
        if i + 1 < len(method_start_end):
            distance_to_next = method_start_end[i + 1]["start_line"] - method["end_line"] - 1
        else:
            distance_to_next = 0  # Für die letzte Methode gibt es keinen Abstand zur nächsten Methode

        # Ausgabe für Debugging und Prüfung
        print(f"{method['method_signature']:<100}{method['start_line']:<12}{method['end_line']:<12}{method_size:<8}{distance_to_next:<30}")

    return method_start_end


# Git-Log-Analyse
def get_line_commits(repo_path, file_path, start_line, end_line):
    """Ruft die Commits für eine bestimmte Zeile ab und gibt die eindeutigen Commits zurück."""
    command = [
        "git",
        "-C",
        repo_path,
        "log",
        "-L",
        f"{start_line},{end_line}:{file_path}"
    ]
    
    try:
        result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        
        if result.returncode == 0:
            commits = result.stdout.strip().splitlines()
            unique_commits = set(commit.split()[1] for commit in commits if commit.startswith("commit"))
            return unique_commits
        else:
            return set()
    except Exception as e:
        return set()


# Methoden parallel verarbeiten
def analyze_method_changes(method):
    """Analyse einzelner Methoden anhand Commits und Statistiken."""
    start_line = method["start_line"]
    end_line = method["end_line"]
    commits = get_line_commits(repo_path, file_path, start_line, end_line)
    
    # Berechne Methode-Größe und andere Details
    method_size = (end_line - start_line + 1)
    
    # Wenn die Methode keine Änderungen hat, einfach weiterleiten
    return {
        "Methoden-Signatur": method["method_signature"],
        "Startzeile": method["start_line"],
        "Endzeile": method["end_line"],
        "Zeilenanzahl": method_size,
        "Anzahl Änderungen": len(commits),
        "Commits": ", ".join(list(commits)),  # Kommaseparierte Commit-Liste
    }


# Methoden erfassen
methods = analyze_methods(lines)

# Methodenanalyse parallel ausführen
method_changes = []
with ThreadPoolExecutor() as executor:
    results = list(tqdm(executor.map(analyze_method_changes, methods), desc="Analysiere Methoden", total=len(methods)))

method_changes.extend(results)

# Ergebnisse in DataFrame speichern
df_methods = pd.DataFrame(method_changes)

# Dateiname ohne Endung extrahieren
base_filename = os.path.basename(file_path)
file_name_without_extension = os.path.splitext(base_filename)[0]

output_path = os.path.join(r"C:\Users\Kon\Documents\gitAnalyse", f"methoden_analyse_{file_name_without_extension}.xlsx")
try:
    df_methods.to_excel(output_path, index=False, engine="openpyxl")
    print(f"Analyse abgeschlossen. Ergebnisse gespeichert unter: {output_path}")
except PermissionError:
    print(f"Fehler: Keine Berechtigung zum Schreiben der Datei. Bitte sicherstellen, dass die Datei nicht geöffnet ist und versuchen Sie es erneut.")
