import os
import ezdxf
from ezdxf.math import Vec2
import argparse
import sys
import shutil

def check_environment_var(env_str: str, fallback: str) -> str:
    out_path = os.environ.get(env_str)
    if out_path:
        return out_path
    print(f"[WARN] Umgebungsvariable {env_str} ist nicht gesetzt oder leer. Verwende '{fallback}'.")
    return fallback

def get_bbox(entities):
    min_x, min_y = float('inf'), float('inf')
    max_x, max_y = float('-inf'), float('-inf')
    for e in entities:
        try:
            # Für POLYLINE-Entities: Bounding Box manuell berechnen
            if e.dxftype() == "POLYLINE":
                if hasattr(e, 'vertices') and len(e.vertices) > 0:
                    for vertex in e.vertices:
                        if hasattr(vertex, 'dxf') and hasattr(vertex.dxf, 'location'):
                            x, y = vertex.dxf.location.x, vertex.dxf.location.y
                            min_x, min_y = min(min_x, x), min(min_y, y)
                            max_x, max_y = max(max_x, x), max(max_y, y)
            else:
                # Für andere Entity-Typen: Standard bbox() verwenden
                box = e.bbox()
                if box:
                    (x1, y1), (x2, y2) = box.extmin, box.extmax
                    min_x, min_y = min(min_x, x1), min(min_y, y1)
                    max_x, max_y = max(max_x, x2), max(max_y, y2)
        except Exception as err:
            print(f"    BBox Fehler für {e.dxftype()}: {err}")
            continue
    if min_x == float('inf'):
        return None
    return Vec2((min_x + max_x) / 2, (min_y + max_y) / 2)

if __name__ == "__main__":
    # Argumentparser für Kommandozeilenoptionen
    parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter")
    parser.add_argument('-i', '--input', type=str, help='Input-Verzeichnis mit SVG/XML-Dateien')
    parser.add_argument('-n', '--name', required=True, type=str, help='Name der zu erzeugenden Bibliothek')
    parser.add_argument('-k', '--keep', action="store_true", help='Behalte converted_dxf Ordner. Sonst Löschen nach erfolgreicher Bibliothekserstellung')

    if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"):
        parser.print_help()
        sys.exit(0)
        
    args = parser.parse_args()

     # Verzeichnisse über Umgebungsvariablen oder Fallback
    if args.input:
        INPUT_DIR = args.input
        print(f"Verwende Input-Verzeichnis: {INPUT_DIR} \n")
    else:
        INPUT_DIR = os.path.join(check_environment_var("PROJECT_WORK", "."), "converted_dxfs")
        print(f"Kein Input-Verzeichnis angegeben, verwende Standard: {INPUT_DIR} \n")

    OUTPUT_FILE = os.path.join(check_environment_var("PROJECT_DATA", "."),"block_libaries", f"{args.name}.dxf")

    doc = ezdxf.new()
    msp = doc.modelspace()

    x_offset = 0
    y_offset = 0
    blocks_in_row = 0

    for filename in os.listdir(INPUT_DIR):
        if not filename.lower().endswith(".dxf"):
            continue

        filepath = os.path.join(INPUT_DIR, filename)
        name = os.path.splitext(filename)[0]

        try:
            src_doc = ezdxf.readfile(filepath)
            src_msp = src_doc.modelspace()
            entities = list(src_msp)
            allowed_types = {"LINE", "LWPOLYLINE", "POLYLINE", "SPLINE", "CIRCLE", "ARC"}
            filtered_entities = [e for e in entities if e.dxftype() in allowed_types]
            entities = filtered_entities
        except Exception as e:
            print(f"Fehler beim Lesen von {filename}: {e}")
            continue

        center = get_bbox(entities)
        if center is None:
            print(f"Keine gültige Geometrie in {filename}")
            continue

        if name in doc.blocks:
            doc.blocks.delete_block(name)

        blk = doc.blocks.new(name=name, base_point=center)

        for e in entities:
            try:
                blk.add_entity(e.copy())
            except Exception as err:
                print(f"Fehler in {filename}: {err}")

        # Platzierung in Reihen und Spalten
        msp.add_blockref(name, insert=(x_offset, y_offset))
        # Text mit Blocknamen über dem Block
        text_y = y_offset + 150  # 150 Einheiten über dem Block
        msp.add_text(name, dxfattribs={'height': 20, 'insert': (x_offset-150, text_y)})
        blocks_in_row += 1
        x_offset += 350  # Abstand zwischen Blöcken in einer Reihe
        if blocks_in_row == 20:
            blocks_in_row = 0
            x_offset = 0
            y_offset -= 500  # Neue Zeile, nach unten versetzt

    print(f"Bibliotheks-DXF gespeichert: {OUTPUT_FILE} \n")
    doc.saveas(OUTPUT_FILE)

    if not args.keep:
        print(f"Keep-Argument nicht gesetzt, lösche Input-Verzeichnis: {INPUT_DIR} \n")
        try:
            if os.path.exists(INPUT_DIR):
                shutil.rmtree(INPUT_DIR)
                print(f"Verzeichnis '{INPUT_DIR}' wurde gelöscht.")
        except Exception as err:
            print(f"[WARN] Konnte '{INPUT_DIR}' nicht löschen: {err}")
