import cv2
import numpy as np
import os
import glob
import pandas as pd
import re
from PIL import Image
from datetime import datetime

# --- PFAD ANPASSEN ---
PFAD = r""

def natural_sort_key(s):
    return [int(text) if text.isdigit() else text.lower()
            for text in re.split('([0-9]+)', s)]

def bild_laden(pfad):
    try:
        stream = np.fromfile(pfad, dtype=np.uint8)
        img = cv2.imdecode(stream, cv2.IMREAD_COLOR)
        return img
    except Exception as e:
        print(f"Fehler beim Laden: {e}")
        return None

# --- NEU: ZEITSTEMPEL AUSLESEN ---
def get_timestamp(path):
    # Versucht, das Aufnahmedatum zu finden
    try:
        img = Image.open(path)
        dt_obj = None
        
        # 1. Versuche Standard EXIF (JPG/TIFF)
        # Tags: 36867 (DateTimeOriginal), 306 (DateTime)
        exif = getattr(img, '_getexif', lambda: None)()
        if exif:
            dt_str = exif.get(36867) or exif.get(306)
            if dt_str:
                return datetime.strptime(str(dt_str), "%Y:%m:%d %H:%M:%S")

        # 2. Versuche TIFF-Tags (falls EXIF leer)
        if hasattr(img, 'tag_v2'):
            dt_str = img.tag_v2.get(306)
            if dt_str:
                return datetime.strptime(str(dt_str), "%Y:%m:%d %H:%M:%S")
                
    except Exception:
        pass
        
    # 3. Notlösung: Dateisystem-Zeit (Änderungsdatum)
    try:
        return datetime.fromtimestamp(os.path.getmtime(path))
    except:
        return None

def smart_ellipse_final_timed():
    input_folder = PFAD
    if not os.path.exists(input_folder):
        print("Pfad nicht gefunden!")
        return

    # 1. Ordner suchen & Sortieren
    entries = [f.path for f in os.scandir(input_folder) if f.is_dir()]
    subfolders = []
    for f in entries:
        if os.path.basename(f).isdigit():
            subfolders.append(f)
    subfolders.sort(key=lambda f: natural_sort_key(os.path.basename(f)))
    
    if not subfolders:
        print("Keine Ordner 1..10 gefunden!")
        return

    print(f"Ordner-Reihenfolge: {[os.path.basename(f) for f in subfolders]}")

    # 2. Bilder sammeln
    all_files = []
    for sf in subfolders:
        unique_files = set()
        patterns = ["*.jpg", "*.JPG", "*.tif", "*.tiff", "*.TIF"]
        for p in patterns:
            unique_files.update(glob.glob(os.path.join(sf, p)))
        
        imgs = sorted(list(unique_files))
        imgs.sort(key=lambda f: natural_sort_key(os.path.basename(f)))
        
        for img_path in imgs:
            all_files.append((img_path, os.path.basename(sf)))

    if not all_files:
        print("Keine Bilder gefunden.")
        return

    print(f"{len(all_files)} Bilder geladen. Ermittle Startzeit...")

    # --- STARTZEIT FESTLEGEN (t0) ---
    start_time = get_timestamp(all_files[0][0])
    if start_time is None:
        print("WARNUNG: Kein Zeitstempel im ersten Bild gefunden! Zeit wird 0 sein.")
        start_time = datetime.now() # Fallback, damit Code nicht crasht

    print(f"Startzeit (t0) ist: {start_time}")

    # --- FENSTER ---
    cv2.namedWindow("Analyse", cv2.WINDOW_NORMAL)
    cv2.resizeWindow("Analyse", 1000, 800)
    
    def nichts(x): pass
    cv2.createTrackbar("Threshold", "Analyse", 120, 255, nichts)
    cv2.createTrackbar("Invertieren", "Analyse", 1, 1, nichts)    
    cv2.createTrackbar("Stab-Winkel", "Analyse", 60, 160, nichts) 

    # --- ROI AUSWAHL ---
    print("Lade erstes Bild für Auswahl...")
    first_img = bild_laden(all_files[0][0])
    h_orig, w_orig = first_img.shape[:2]
    screen_h = 800
    scale = screen_h / h_orig if h_orig > screen_h else 1.0
    img_select = cv2.resize(first_img, None, fx=scale, fy=scale)
    
    roi_small = cv2.selectROI("Analyse", img_select, showCrosshair=True)
    x_fixed = int(roi_small[0] / scale)
    y_fixed = int(roi_small[1] / scale)
    w_fixed = int(roi_small[2] / scale)
    h_fixed = int(roi_small[3] / scale)
    
    if w_fixed == 0 or h_fixed == 0: return

    ergebnisse = []

    # --- HAUPTSCHLEIFE ---
    for i, (file_path, folder_name) in enumerate(all_files):
        filename = os.path.basename(file_path)
        img_raw = bild_laden(file_path)
        if img_raw is None: continue

        # ZEIT BERECHNEN
        current_time = get_timestamp(file_path)
        time_diff = 0
        if current_time and start_time:
            delta = current_time - start_time
            time_diff = delta.total_seconds()

        # ROI Crop
        y = int(max(0, y_fixed))
        x = int(max(0, x_fixed))
        h = int(min(h_fixed, h_orig - y))
        w = int(min(w_fixed, w_orig - x))
        crop = img_raw[y:y+h, x:x+w].copy()

        saved = False
        while True:
            th_val = cv2.getTrackbarPos("Threshold", "Analyse")
            inv_val = cv2.getTrackbarPos("Invertieren", "Analyse")
            angle_cut = cv2.getTrackbarPos("Stab-Winkel", "Analyse")

            gray = cv2.cvtColor(crop, cv2.COLOR_BGR2GRAY)
            blurred = cv2.GaussianBlur(gray, (5, 5), 0)
            thresh_mode = cv2.THRESH_BINARY_INV if inv_val == 1 else cv2.THRESH_BINARY
            _, mask = cv2.threshold(blurred, th_val, 255, thresh_mode)
            mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((3,3),np.uint8), iterations=2)
            contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            
            vis_img = crop.copy()
            d_ellipse_min = 0 # Das ist der Durchmesser!
            
            if contours:
                c = max(contours, key=cv2.contourArea)
                M = cv2.moments(c)
                if M["m00"] > 0:
                    cX = int(M["m10"] / M["m00"])
                    cY = int(M["m01"] / M["m00"])
                    pts = c.squeeze()
                    if pts.ndim == 1: pts = pts.reshape(-1, 2)
                    
                    # Winkel Filter
                    angles_rad = np.arctan2(pts[:, 1] - cY, pts[:, 0] - cX)
                    angles_deg = np.degrees(angles_rad)
                    diff = np.abs(angles_deg - (-90))
                    diff = np.minimum(diff, 360 - diff)
                    valid_mask = diff > (angle_cut / 2.0)
                    valid_pts = pts[valid_mask]
                    invalid_pts = pts[~valid_mask]
                    
                    # Zeichnen
                    for p in valid_pts[::3]: vis_img[p[1], p[0]] = (255, 0, 0)
                    for p in invalid_pts[::3]: vis_img[p[1], p[0]] = (0, 0, 255)

                    if len(valid_pts) > 10:
                        try:
                            ellipse = cv2.fitEllipse(valid_pts)
                            cv2.ellipse(vis_img, ellipse, (0, 255, 0), 1)
                            (ex, ey), (MA, ma), angle = ellipse
                            d_ellipse_min = min(MA, ma) # Breite = Durchmesser
                            cv2.drawMarker(vis_img, (int(ex), int(ey)), (0, 255, 0), cv2.MARKER_CROSS, 10, 1)
                        except: pass

            info_txt = f"{folder_name}/{filename} | t={time_diff:.0f}s"
            cv2.putText(vis_img, info_txt, (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1)
            cv2.putText(vis_img, f"D: {d_ellipse_min:.2f} px", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)

            cv2.imshow("Analyse", vis_img)
            k = cv2.waitKey(20) & 0xFF
            if k == 27:
                cv2.destroyAllWindows()
                if ergebnisse: pd.DataFrame(ergebnisse).to_excel(os.path.join(input_folder, "Abbruch_Daten.xlsx"))
                return
            elif k == 32:
                ergebnisse.append({
                    "Ordner": folder_name,
                    "Dateiname": filename,
                    "Zeit_seit_Start_sek": int(time_diff), # Neue Spalte
                    "Durchmesser_Kugel_px": round(d_ellipse_min, 2), # Neue Spalte (klarer Name)
                    "Stab_Winkel": angle_cut
                })
                print(f"[{folder_name}] {filename} (t={int(time_diff)}s) -> {d_ellipse_min:.2f}")
                saved = True
                break
        if not saved: break

    cv2.destroyAllWindows()
    df = pd.DataFrame(ergebnisse)
    out = os.path.join(input_folder, "Ergebnisse_Final_Zeit.xlsx")
    df.to_excel(out, index=False)
    print(f"FERTIG! Daten in: {out}")

if __name__ == "__main__":
    smart_ellipse_final_timed()