#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
create_example.py - Erzeugt Test-DXF-Dateien für verschiedene Testszenarien

Dieses Skript generiert synthetische DXF-Testdateien mit definierten Layouts
für verschiedene Testfälle (Nummerierung, SPS, Erdung, etc.).
"""

import argparse
import sys
import os
import json
from pathlib import Path
import ezdxf

# Umgebungsvariablen
PROJECT = os.getenv('PROJECT', Path(__file__).parent.parent.absolute())
PROJECT_TEST = os.getenv('PROJECT_TEST', os.path.join(PROJECT, 'testdata'))
PROJECT_CFG = os.getenv('PROJECT_CFG', os.path.join(PROJECT, 'cfg'))


class TestDataGenerator:
    """Generiert Test-DXF-Dateien für verschiedene Szenarien"""

    def __init__(self, filename, scene_name, config_file=None):
        self.filename = filename
        self.scene_name = scene_name
        self.doc = None
        self.msp = None
        self.config = None

        # Lade Config-Datei (muss immer angegeben werden)
        if config_file:
            self.load_config(config_file)

    def load_config(self, config_file):
        """
        Lädt die JSON-Konfigurationsdatei

        Args:
            config_file: Pfad zur JSON-Config-Datei
        """
        config_path = Path(config_file)
        if not config_path.is_absolute():
            config_path = Path(PROJECT_CFG) / config_file

        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                self.config = json.load(f)
            print(f"Config geladen: {config_path}")
        except FileNotFoundError:
            print(f"FEHLER: Config-Datei nicht gefunden: {config_path}")
            self.config = None
        except json.JSONDecodeError as e:
            print(f"FEHLER beim Parsen der Config-Datei: {e}")
            self.config = None

    def create_document(self):
        """Erstellt ein neues DXF-Dokument"""
        self.doc = ezdxf.new('R2010')
        self.msp = self.doc.modelspace()

        # Erstelle textstyle3 für die Attribute
        self.create_textstyle()

        # Erstelle Layer mit korrekten Farben
        self.create_layers()

        return self.doc

    def create_textstyle(self):
        """Erstellt den textstyle3 für Attribute"""
        if 'textstyle3' not in self.doc.styles:
            self.doc.styles.new('textstyle3', dxfattribs={
                'font': 'arial.ttf',
                'width': 1.0
            })

    def create_layers(self):
        """
        Erstellt alle benötigten Layer mit korrekten Farben
        Basiert auf Analyse von easy.dxf
        """
        # Layer-Definitionen mit Farben
        layer_defs = [
            {'name': '0', 'color': 7},  # Standard-Layer
            {'name': 'ILS_MOTOR', 'color': 7},
            {'name': 'ILS_RENAMER', 'color': 1},  # Rot
            {'name': 'TEXT-D', 'color': -7},  # Ausgeschaltet (negativ)
            {'name': 'TEXT-E', 'color': 7},
            {'name': 'TEXT-ES', 'color': 7},
            {'name': 'TEXT-F', 'color': 7},
            {'name': 'TEXT-I', 'color': 7}
        ]

        for layer_def in layer_defs:
            if layer_def['name'] not in self.doc.layers:
                self.doc.layers.new(layer_def['name'], dxfattribs={
                    'color': layer_def['color']
                })

    def calculate_symbol_extent(self, io_text):
        """
        Berechnet die ungefähre Ausdehnung eines io-Symbols basierend auf der IO-Länge

        Basierend auf Analyse von IO=MA0062 (6 Zeichen):
        - Bounding Box: 1208.94 x 380.94 Einheiten
        - ~201.49 Einheiten Breite pro Zeichen
        - ~380.94 Einheiten Höhe (konstant)

        Args:
            io_text: Text des IO-Attributs (z.B. "MA-1@@")

        Returns:
            (width, height) in DXF-Einheiten
        """
        char_count = len(io_text)
        width_per_char = 201.49
        fixed_height = 380.94

        width = char_count * width_per_char
        height = fixed_height

        return (width, height)

    def create_io_block(self):
        """
        Erstellt den io-Block mit allen Attribut-Definitionen
        Basiert auf dem io-Block aus easy.dxf (IO=MA0062)

        Returns:
            Block-Definition
        """
        if 'io' in self.doc.blocks:
            return self.doc.blocks['io']

        # Erstelle neuen Block
        io_block = self.doc.blocks.new('io')

        # Attribut-Definitionen basierend auf ILS_Motor-790902001 aus Nummerierung_IO.dxf
        # invisible=True: ID, BEZEICHNUNG, KENNZEICHNUNG, ARTIKELNR, ARTIKELBEZEICHN, TEXT-I
        # invisible=False: IO, VERW, SPS, REALE_POSITION, TEXT-D, TEXT-E, TEXT-ES, TEXT-F
        attrib_defs = [
            {
                'tag': 'REALE_POSITION',
                'insert': (0.0, 230.0, 0.0),
                'height': 50.0,
                'default': 'x',
                'layer': 'ILS_MOTOR',
                'invisible': False
            },
            {
                'tag': 'SPS',
                'insert': (0.0, 130.37, 0.0),
                'height': 125.0,
                'default': '1',
                'layer': 'ILS_MOTOR',
                'invisible': False
            },
            {
                'tag': 'IO',
                'insert': (103.88, 130.37, 0.0),
                'height': 125.0,
                'default': 'MA0000',
                'layer': 'ILS_MOTOR',
                'invisible': False
            },
            {
                'tag': 'TEXT-D',
                'insert': (772.87, 110.44, 0.0),
                'height': 63.75,
                'default': '',
                'layer': 'TEXT-D',
                'invisible': False
            },
            {
                'tag': 'TEXT-E',
                'insert': (772.87, 110.44, 0.0),
                'height': 63.75,
                'default': '',
                'layer': 'TEXT-E',
                'invisible': False
            },
            {
                'tag': 'TEXT-ES',
                'insert': (772.87, 110.44, 0.0),
                'height': 63.75,
                'default': '',
                'layer': 'TEXT-ES',
                'invisible': False
            },
            {
                'tag': 'TEXT-F',
                'insert': (772.87, 110.44, 0.0),
                'height': 63.75,
                'default': '',
                'layer': 'TEXT-F',
                'invisible': False
            },
            {
                'tag': 'TEXT-I',
                'insert': (772.87, 110.44, 0.0),
                'height': 63.75,
                'default': '',
                'layer': 'TEXT-I',
                'invisible': True  # Unsichtbar
            },
            {
                'tag': 'VERW',
                'insert': (6.92, 20.78, 0.0),
                'height': 80.0,
                'default': 'ILS-M0000',
                'layer': 'ILS_MOTOR',
                'invisible': False
            },
            {
                'tag': 'ID',
                'insert': (0.0, 0.73, 0.0),
                'height': 120.0,
                'default': '',
                'layer': 'ILS_MOTOR',
                'invisible': True  # Unsichtbar
            },
            {
                'tag': 'BEZEICHNUNG',
                'insert': (0.0, -67.05, 0.0),
                'height': 63.75,
                'default': 'Motor MA0000',
                'layer': 'ILS_MOTOR',
                'invisible': True  # Unsichtbar
            },
            {
                'tag': 'KENNZEICHNUNG',
                'insert': (0.0, -155.33, 0.0),
                'height': 63.75,
                'default': '=A01+UH00',
                'layer': 'ILS_MOTOR',
                'invisible': True  # Unsichtbar
            },
            {
                'tag': 'ARTIKELNR',
                'insert': (0.0, -248.90, 0.0),
                'height': 63.75,
                'default': '790902001',
                'layer': 'ILS_MOTOR',
                'invisible': True  # Unsichtbar
            },
            {
                'tag': 'ARTIKELBEZEICHN',
                'insert': (0.0, -332.68, 0.0),
                'height': 63.75,
                'default': 'E-Teile fuer SEW Motor ASE1 - HAN10ES - BG',
                'layer': 'ILS_MOTOR',
                'invisible': True  # Unsichtbar
            }
        ]

        # Füge alle Attribut-Definitionen hinzu
        for attrib_def in attrib_defs:
            # Berechne flags: Bit 0 = invisible
            flags = 1 if attrib_def['invisible'] else 0

            io_block.add_attdef(
                tag=attrib_def['tag'],
                insert=attrib_def['insert'],
                text=attrib_def['default'],
                dxfattribs={
                    'height': attrib_def['height'],
                    'layer': attrib_def['layer'],
                    'color': 256,  # BYLAYER
                    'style': 'textstyle3',
                    'rotation': 0,
                    'halign': 0,
                    'valign': 0,
                    'flags': flags
                }
            )

        return io_block

    def save(self, output_dir=None):
        """Speichert das DXF-Dokument"""
        if output_dir is None:
            output_dir = PROJECT_TEST

        output_path = os.path.join(output_dir, self.filename)
        self.doc.saveas(output_path)
        print(f"Test-DXF erstellt: {output_path}")
        return output_path

    def load_block_from_file(self, source_file, block_name):
        """
        Lädt einen Block aus einer anderen DXF-Datei

        Args:
            source_file: Pfad zur Quell-DXF-Datei
            block_name: Name des zu ladenden Blocks

        Returns:
            Block-Definition oder None
        """
        try:
            source_doc = ezdxf.readfile(source_file)
            if block_name in source_doc.blocks:
                # Block in das Zieldokument kopieren
                source_block = source_doc.blocks.get(block_name)
                if block_name not in self.doc.blocks:
                    new_block = self.doc.blocks.new(block_name)
                    # Kopiere alle Entities aus dem Quellblock (inkl. ATTDEF)
                    for entity in source_block:
                        try:
                            new_block.add_foreign_entity(entity, copy=True)
                        except Exception as e:
                            print(f"Warnung: Konnte Entity nicht kopieren: {e}")
                            # Versuche direktes Klonen
                            try:
                                cloned = entity.copy()
                                new_block.add_entity(cloned)
                            except:
                                pass
                return self.doc.blocks.get(block_name)
            else:
                print(f"Warnung: Block '{block_name}' nicht in {source_file} gefunden")
                return None
        except Exception as e:
            print(f"Fehler beim Laden von Block '{block_name}': {e}")
            import traceback
            traceback.print_exc()
            return None

    def create_renamer_attrib_block(self, block_name, attrib_tags, frame_type='MA'):
        """
        Erstellt einen Block mit ATTDEF-Attributen für Renamer-Frames

        Args:
            block_name: Name des Attribut-Blocks (z.B. 'RENAMER_ATTRIB_MA')
            attrib_tags: Liste der Attribut-Tags (z.B. ['NAME', 'KENNZEICHNUNG', ...])
            frame_type: 'MA' oder 'MULTI' für Frame-Typ

        Returns:
            Block-Definition
        """
        if block_name in self.doc.blocks:
            return self.doc.blocks[block_name]

        attrib_block = self.doc.blocks.new(block_name)

        # Hole Positionen aus Config, falls vorhanden
        if self.config and 'general' in self.config:
            general = self.config['general']
            if frame_type == 'MA' and 'ma_frame' in general:
                config_positions = general['ma_frame'].get('attdef_positions', {})
            elif frame_type == 'MULTI' and 'multi_frame' in general:
                config_positions = general['multi_frame'].get('attdef_positions', {})
            else:
                config_positions = {}
        else:
            config_positions = {}

        # Definiere Standard-Positionen und Werte für Attribute (Fallback)
        default_definitions = {
            'NAME': {'insert': (10, 50), 'default': 'MA@@', 'height': 21.25},
            'NAME1': {'insert': (10, 80), 'default': 'BG1@@@', 'height': 21.25},
            'NAME2': {'insert': (10, 60), 'default': 'MB1@@@', 'height': 21.25},
            'NAME3': {'insert': (10, 40), 'default': '', 'height': 21.25},
            'KENNZEICHNUNG': {'insert': (10, 20), 'default': '=A01+UC0101', 'height': 21.25},
            'LAYER_NAME': {'insert': (10, 0), 'default': 'ILS_MOTOR', 'height': 21.25},
            'LAYER_NAME1': {'insert': (10, -20), 'default': 'ILS_Eingang', 'height': 21.25},
            'LAYER_NAME2': {'insert': (10, -40), 'default': 'ILS_Ausgang', 'height': 21.25},
            'LAYER_NAME3': {'insert': (10, -60), 'default': '', 'height': 21.25},
            'DIRECTION': {'insert': (10, -80), 'default': 'LEFT_RIGHT', 'height': 21.25},
            'ID': {'insert': (10, -100), 'default': '', 'height': 21.25}
        }

        # Füge nur die angeforderten Attribute hinzu
        for tag in attrib_tags:
            if tag in default_definitions:
                default_def = default_definitions[tag]

                # Verwende Config-Werte, falls vorhanden, sonst Defaults
                if tag in config_positions and not tag.startswith('_'):
                    config_pos = config_positions[tag]
                    x = config_pos.get('x', default_def['insert'][0])
                    y = config_pos.get('y', default_def['insert'][1])
                    height = config_pos.get('height', default_def['height'])
                else:
                    x, y = default_def['insert']
                    height = default_def['height']

                attrib_block.add_attdef(
                    tag=tag,
                    insert=(x, y),
                    text=default_def['default'],
                    dxfattribs={
                        'height': height,
                        'layer': 'ILS_RENAMER',
                        'color': 1,
                        'style': 'textstyle3'
                    }
                )

        return attrib_block

    def create_renamer_frame(self, insert_point, width, height, name, kennzeichnung,
                            layer_name, direction, use_polyline=False, frame_type='MA'):
        """
        Erstellt einen Renamer-Rahmen mit zweistufiger Block-Struktur auf Layer ILS_RENAMER

        Struktur:
        - Äußerer Block (RENAMER_xxx):
          1. LWPOLYLINE (umschließende Polylinie)
          2. Block-Referenz mit Attributen (RENAMER_ATTRIB_xxx)

        Args:
            insert_point: (x, y) Position des Rahmens
            width: Breite des Rahmens
            height: Höhe des Rahmens
            name: NAME-Attribut (oder NAME1 für Multi-Layer)
            kennzeichnung: KENNZEICHNUNG-Attribut
            layer_name: LAYER_NAME-Attribut (oder LAYER_NAME1 für Multi-Layer)
            direction: DIRECTION-Attribut
            use_polyline: Wird ignoriert (für Kompatibilität)
            frame_type: 'MA' für einfachen Frame, 'MULTI' für Multi-Layer Frame
        """
        x, y = insert_point

        # Bestimme Attribut-Tags basierend auf Frame-Typ
        if frame_type == 'MA':
            attrib_tags = ['NAME', 'KENNZEICHNUNG', 'LAYER_NAME', 'DIRECTION']
            attrib_block_name = 'RENAMER_ATTRIB_MA'
        else:  # MULTI
            attrib_tags = ['NAME1', 'NAME2', 'NAME3', 'KENNZEICHNUNG',
                          'LAYER_NAME1', 'LAYER_NAME2', 'LAYER_NAME3', 'DIRECTION', 'ID']
            attrib_block_name = 'RENAMER_ATTRIB_MULTI'

        # Erstelle Attribut-Block (wiederverwendbar) mit Config-Unterstützung
        self.create_renamer_attrib_block(attrib_block_name, attrib_tags, frame_type=frame_type)

        # Erstelle äußeren Renamer-Block mit eindeutigem Namen (inkl. Position und Größe)
        # Jeder Rahmen bekommt einen eindeutigen Namen basierend auf Position
        outer_block_name = f"RENAMER_{name.replace('@', '').replace('-', '_')}_{int(x)}_{int(y)}"
        if outer_block_name not in self.doc.blocks:
            outer_block = self.doc.blocks.new(outer_block_name)

            # 1. Füge LWPOLYLINE hinzu (umschließende Polylinie)
            points = [
                (0, 0),
                (width, 0),
                (width, height),
                (0, height),
                (0, 0)
            ]
            outer_block.add_lwpolyline(points, dxfattribs={
                'layer': 'ILS_RENAMER',
                'color': 1
            })

            # 2. Füge Block-Referenz mit Attributen hinzu
            # Position an der linken oberen Ecke des Rahmens
            attrib_insert_pos = (10, height - 30)  # Linke obere Ecke mit kleinem Abstand
            attrib_blockref = outer_block.add_blockref(
                attrib_block_name,
                insert=attrib_insert_pos,
                dxfattribs={'layer': 'ILS_RENAMER'}
            )

            # Setze Attribut-Werte auf der inneren Block-Referenz
            if frame_type == 'MA':
                attrib_blockref.add_auto_attribs({
                    'NAME': name,
                    'KENNZEICHNUNG': kennzeichnung,
                    'LAYER_NAME': layer_name,
                    'DIRECTION': direction
                })
            else:  # MULTI - würde später für BG/MG/POT verwendet
                # Placeholder für Multi-Layer Frame
                pass

        # Füge Block-Referenz im Modelspace ein
        blockref = self.msp.add_blockref(
            outer_block_name,
            insert=(x, y),
            dxfattribs={'layer': 'ILS_RENAMER'}
        )

    def create_polyline_renamer_frame(self, path_points, name, kennzeichnung, layer_name, direction):
        """
        Erstellt einen Renamer-Rahmen mit Polyline-Pfad

        Struktur:
        - Block (RENAMER_POLYLINE_xxx):
          1. LWPOLYLINE (Pfad durch die Punkte)
          2. Block-Referenz mit Attributen (RENAMER_ATTRIB_MA)

        Args:
            path_points: Liste von Dictionaries mit 'x' und 'y' Koordinaten
            name: NAME-Attribut
            kennzeichnung: KENNZEICHNUNG-Attribut
            layer_name: LAYER_NAME-Attribut
            direction: DIRECTION-Attribut (z.B. 'POLYLINE_PATH')
        """
        # Erstelle Attribut-Block (wiederverwendbar)
        attrib_tags = ['NAME', 'KENNZEICHNUNG', 'LAYER_NAME', 'DIRECTION']
        attrib_block_name = 'RENAMER_ATTRIB_MA'
        self.create_renamer_attrib_block(attrib_block_name, attrib_tags, frame_type='MA')

        # Erstelle eindeutigen Block-Namen basierend auf erstem Punkt
        first_point = path_points[0] if path_points else {'x': 0, 'y': 0}
        block_name = f"RENAMER_POLYLINE_{name.replace('@', '').replace('-', '_')}_{int(first_point['x'])}_{int(first_point['y'])}"

        if block_name not in self.doc.blocks:
            renamer_block = self.doc.blocks.new(block_name)

            # 1. Füge LWPOLYLINE hinzu (Pfad)
            # Konvertiere Punkte von Dict zu Tupeln
            points = [(p['x'], p['y']) for p in path_points]

            renamer_block.add_lwpolyline(points, dxfattribs={
                'layer': 'ILS_RENAMER',
                'color': 1
            })

            # 2. Füge Block-Referenz mit Attributen hinzu
            # Position neben dem ersten Punkt des Pfades (mit kleinem Offset)
            first_x = points[0][0]
            first_y = points[0][1]
            attrib_insert_pos = (first_x + 10, first_y + 30)  # Offset vom ersten Punkt
            attrib_blockref = renamer_block.add_blockref(
                attrib_block_name,
                insert=attrib_insert_pos,
                dxfattribs={'layer': 'ILS_RENAMER'}
            )

            # Setze Attribut-Werte
            attrib_blockref.add_auto_attribs({
                'NAME': name,
                'KENNZEICHNUNG': kennzeichnung,
                'LAYER_NAME': layer_name,
                'DIRECTION': direction
            })

        # Füge Block-Referenz im Modelspace ein (am Ursprung, da Pfad absolute Koordinaten hat)
        blockref = self.msp.add_blockref(
            block_name,
            insert=(0, 0),
            dxfattribs={'layer': 'ILS_RENAMER'}
        )

    def generate_nummerierung(self, scene_name='Nummerierung1'):
        """
        Generiert Testdaten für Nummerierung-Szenario

        Verwendet entweder die JSON-Config oder Hard-coded Defaults

        Args:
            scene_name: Name der Testszene (z.B. 'Nummerierung1', 'Nummerierung2')
        """
        print(f"Generiere Nummerierung-Testdaten ({scene_name})...")

        # Erstelle io-Block direkt (ohne Referenzdatei)
        io_block = self.create_io_block()

        if io_block is None:
            print("Fehler: io-Block konnte nicht erstellt werden")
            return

        # Wenn Config geladen ist, verwende sie, ansonsten Hard-coded Defaults
        if self.config and 'test_scenes' in self.config and scene_name in self.config['test_scenes']:
            print(f"Verwende JSON-Config für {scene_name}...")
            self._generate_nummerierung_from_config(scene_name)
        else:
            print("Verwende Hard-coded Defaults für Nummerierung...")
            self._generate_nummerierung_hardcoded()

    def _generate_ma_group(self, group, ma_defaults, width_per_char, fixed_height, spacing_factor, y_offsets_list):
        """
        Generiert eine Gruppe von MA-Symbolen

        Args:
            group: Dict mit Gruppen-Config (name, count, layout_type, base_x, base_y, spacing)
            ma_defaults: Dict mit MA-Default-Attributen
            width_per_char: Breite pro Zeichen
            fixed_height: Fixe Symbol-Höhe
            spacing_factor: Spacing-Faktor zwischen Symbolen
            y_offsets_list: Liste von Y-Offsets für horizontal_offset Layout
        """
        name = group['name']
        count = group['count']
        layout_type = group['layout_type']
        base_x = group['base_x']
        base_y = group['base_y']

        # Extrahiere IO-Pattern aus Name (z.B. "MA-1@@_top" -> "MA-1@@")
        io_pattern = name.split('_')[0]

        # Berechne Symbol-Ausdehnung
        symbol_width = len(io_pattern) * width_per_char

        # Berechne Spacing
        if layout_type in ['horizontal', 'horizontal_offset']:
            actual_spacing = symbol_width * spacing_factor
        else:
            actual_spacing = 0

        # Hole Attribute aus ma_defaults
        attributes = ma_defaults.get('attributes', {})
        layer = ma_defaults.get('layer', 'ILS_MOTOR')

        # Generiere Symbole basierend auf Layout-Typ
        for i in range(count):
            if layout_type == 'single':
                x, y = base_x, base_y
            elif layout_type == 'horizontal':
                x = base_x + i * actual_spacing
                y = base_y
            elif layout_type == 'horizontal_offset':
                x = base_x + i * actual_spacing
                y_offset = y_offsets_list[i % len(y_offsets_list)]
                y = base_y + y_offset
            else:
                print(f"Unbekannter Layout-Typ: {layout_type}")
                continue

            # Erstelle Block-Referenz
            # Der Insert-Punkt soll an der oberen linken Ecke des TEXT-D liegen
            # TEXT-D ist bei (772.87, 110.44) relativ zum Block, Höhe 63.75
            # Die obere linke Ecke von TEXT-D ist bei (772.87, 110.44 + 63.75) = (772.87, 174.19) relativ zum Block
            # Daher muss der Block um diese Werte verschoben werden
            text_d_x_offset = 772.87
            text_d_y_offset = 110.44 + 63.75  # Basis + Höhe = obere linke Ecke
            block_insert_x = x - text_d_x_offset
            block_insert_y = y - text_d_y_offset
            
            blockref = self.msp.add_blockref(
                'io',
                insert=(block_insert_x, block_insert_y),
                dxfattribs={'layer': layer}
            )

            # Setze Attribute (dynamisch IO und BEZEICHNUNG)
            attrib_values = attributes.copy()
            attrib_values['IO'] = io_pattern
            attrib_values['BEZEICHNUNG'] = f"Motor {io_pattern}"

            blockref.add_auto_attribs(attrib_values)

    def _generate_nummerierung_from_config(self, scene_name='Nummerierung1'):
        """
        Generiert Nummerierung-Testdaten aus JSON-Config

        Args:
            scene_name: Name der Testszene in der Config
        """
        scene = self.config['test_scenes'][scene_name]
        ma_defaults = self.config.get('ma_defaults', {})
        general = self.config.get('general', {})

        # Hole Dimensions aus Config
        dimensions = ma_defaults.get('dimensions', {})
        width_per_char = dimensions.get('width_per_char', 201.49)
        fixed_height = dimensions.get('fixed_height', 380.94)

        # Hole Layout-Einstellungen
        layout = general.get('layout', {})
        spacing_factor = layout.get('symbol_spacing_factor', 1.2)
        y_offsets_list = layout.get('horizontal_offset_y_offsets', [0, -50, 50])

        # Generiere MA-Gruppen aus Config
        for group in scene.get('ma_groups', []):
            self._generate_ma_group(group, ma_defaults, width_per_char, fixed_height, spacing_factor, y_offsets_list)

        # Generiere Renamer-Rahmen aus Config
        for frame_config in scene.get('renaming_frames', []):
            frame_type = frame_config.get('type', 'rectangle')

            if frame_type == 'polyline_path':
                # Polyline-Pfad Frame
                self.create_polyline_renamer_frame(
                    path_points=frame_config['path_points'],
                    name=frame_config['name'],
                    kennzeichnung=frame_config['kennzeichnung'],
                    layer_name=frame_config['layer_name'],
                    direction=frame_config['direction']
                )
            else:
                # Standard Rectangle Frame
                self.create_renamer_frame(
                    insert_point=(frame_config['x'], frame_config['y']),
                    width=frame_config['width'],
                    height=frame_config['height'],
                    name=frame_config['name'],
                    kennzeichnung=frame_config['kennzeichnung'],
                    layer_name=frame_config['layer_name'],
                    direction=frame_config['direction'],
                    use_polyline=frame_config.get('use_polyline', False)
                )

    def _generate_nummerierung_hardcoded(self):
        """Generiert Nummerierung-Testdaten mit Hard-coded Werten (Fallback)"""

        # Berechne Symbol-Ausdehnung für korrekte Positionierung
        ma1_width, ma1_height = self.calculate_symbol_extent('MA-1@@')
        ma2_width, ma2_height = self.calculate_symbol_extent('MA-2@@')

        # Abstand zwischen Symbolen (20% der Breite als Puffer)
        spacing = ma1_width * 1.2

        # Definiere Positionen
        # Rechts oben: 3x MA-1@@ nebeneinander
        top_right_y = 1000
        top_right_x_start = 1500

        # Der Insert-Punkt soll an der oberen linken Ecke des TEXT-D liegen
        text_d_x_offset = 772.87
        text_d_y_offset = 110.44 + 63.75  # Basis + Höhe = obere linke Ecke

        for i in range(3):
            x = top_right_x_start + i * spacing
            block_insert_x = x - text_d_x_offset
            block_insert_y = top_right_y - text_d_y_offset
            blockref = self.msp.add_blockref(
                'io',
                insert=(block_insert_x, block_insert_y),
                dxfattribs={'layer': 'ILS_MOTOR'}
            )
            # Erzeuge Attribut-Instanzen aus ATTDEFs mit Werten
            blockref.add_auto_attribs({
                'SPS': '1',
                'IO': 'MA-1@@',
                'VERW': 'Motor',
                'BEZEICHNUNG': 'Motor MA-1@@',
                'ARTIKELNR': '790902001',
                'ARTIKELBEZEICHN': 'E-Teile für SEW Motor ASE1-HAN10ES-BG',
                'KENNZEICHNUNG': '=A01+UH00',
                'TEXT-D': '',
                'TEXT-E': '',
                'TEXT-ES': '',
                'TEXT-F': '',
                'TEXT-I': '',
                'ID': '',
                'REALE_POSITION': 'x',
            })

        # Links unten: 1x MA-1@@
        left_bottom_x = 500
        left_bottom_y = 200
        # Der Insert-Punkt soll an der oberen linken Ecke des TEXT-D liegen
        text_d_x_offset = 772.87
        text_d_y_offset = 110.44 + 63.75  # Basis + Höhe = obere linke Ecke
        block_insert_x = left_bottom_x - text_d_x_offset
        block_insert_y = left_bottom_y - text_d_y_offset
        blockref = self.msp.add_blockref(
            'io',
            insert=(block_insert_x, block_insert_y),
            dxfattribs={'layer': 'ILS_MOTOR'}
        )
        blockref.add_auto_attribs({
            'SPS': '1',
            'IO': 'MA-1@@',
            'VERW': 'Motor',
            'BEZEICHNUNG': 'Motor MA-1@@',
            'ARTIKELNR': '790902001',
            'ARTIKELBEZEICHN': 'E-Teile für SEW Motor ASE1-HAN10ES-BG',
            'KENNZEICHNUNG': '=A01+UH00',
            'TEXT-D': '',
            'TEXT-E': '',
            'TEXT-F': '',
            'TEXT-ES': '',
            'ID': '',
            'REALE_POSITION': 'x'
        })

        # Rechts unten: 3x MA-2@@ leicht versetzt
        bottom_right_y_start = 400
        bottom_right_x_start = top_right_x_start
        y_offsets = [0, -50, 50]  # Leichte vertikale Versetzung (angepasst an Symbol-Höhe)

        # Der Insert-Punkt soll an der oberen linken Ecke des TEXT-D liegen
        text_d_x_offset = 772.87
        text_d_y_offset = 110.44 + 63.75  # Basis + Höhe = obere linke Ecke

        for i in range(3):
            x = bottom_right_x_start + i * spacing
            y = bottom_right_y_start + y_offsets[i]
            block_insert_x = x - text_d_x_offset
            block_insert_y = y - text_d_y_offset
            blockref = self.msp.add_blockref(
                'io',
                insert=(block_insert_x, block_insert_y),
                dxfattribs={'layer': 'ILS_MOTOR'}
            )
            blockref.add_auto_attribs({
                'SPS': '1',
                'IO': 'MA-2@@',
                'VERW': 'Motor',
                'BEZEICHNUNG': 'Motor MA-2@@',
                'ARTIKELNR': '790902001',
                'ARTIKELBEZEICHN': 'E-Teile für SEW Motor ASE1-HAN10ES-BG',
                'KENNZEICHNUNG': '=A01+UH00',
                'TEXT-D': '',
                'TEXT-ES': '',
                'TEXT-F': '',
                'ID': '',
                'REALE_POSITION': 'x'
            })

        # Renamer-Rahmen erstellen (mit angepassten Größen basierend auf Symbol-Ausdehnung)
        # Puffer für Rahmen
        frame_padding = 100

        # Rahmen 1: Rechts oben (Rechteck) - umschließt die 3 MA-1@@
        frame1_width = 3 * spacing + ma1_width * 0.2
        frame1_height = ma1_height + 2 * frame_padding
        self.create_renamer_frame(
            insert_point=(top_right_x_start - frame_padding, top_right_y + frame_padding),
            width=frame1_width,
            height=frame1_height,
            name='MA-1@@',
            kennzeichnung='A01+UH00',
            layer_name='ILS_MOTOR',
            direction='LEFT_RIGHT',
            use_polyline=False
        )

        # Rahmen 2: Links unten (Polylinie) - umschließt das einzelne MA-1@@
        # Schmaler machen - nur 15% breiter als das Symbol
        frame2_padding = 50  # Kleinerer Puffer für schmalen Rahmen
        frame2_width = ma1_width * 1.15
        frame2_height = ma1_height + 2 * frame2_padding
        self.create_renamer_frame(
            insert_point=(left_bottom_x - frame2_padding, left_bottom_y - frame2_padding),
            width=frame2_width,
            height=frame2_height,
            name='MA-1@@',
            kennzeichnung='A01+UH00',
            layer_name='ILS_MOTOR',
            direction='TOP_BOTTOM/LEFT_RIGHT',
            use_polyline=True
        )

        # Rahmen 3: Rechts unten (Rechteck) - umschließt die 3 MA-2@@
        # Berücksichtige die vertikalen Offsets (max offset = 50)
        frame3_width = 3 * spacing + ma2_width * 0.2
        frame3_height = ma2_height + 2 * frame_padding + 100  # Extra für y_offsets
        self.create_renamer_frame(
            insert_point=(bottom_right_x_start - frame_padding, bottom_right_y_start - frame_padding - 50),
            width=frame3_width,
            height=frame3_height,
            name='MA-2@@',
            kennzeichnung='A01+UH00',
            layer_name='ILS_MOTOR',
            direction='TOP_BOTTOM',
            use_polyline=False
        )

    def generate(self):
        """Generiert die Testdaten basierend auf dem Test-Typ"""
        self.create_document()

        # Prüfe ob Scene in Config existiert
        if not self.config:
            print("FEHLER: Keine Config-Datei geladen")
            return False
        
        if 'test_scenes' not in self.config:
            print("FEHLER: Config enthält keinen 'test_scenes' Abschnitt")
            return False
        
        if self.scene_name not in self.config['test_scenes']:
            print(f"FEHLER: Scene '{self.scene_name}' nicht in Config gefunden")
            print(f"Verfügbare Scenes: {', '.join(self.config['test_scenes'].keys())}")
            return False
        
        # Generiere nur Nummerierung (andere Test-Typen werden später unterstützt)
        self.generate_nummerierung(self.scene_name)
        
        return True


def main():
    """Hauptfunktion mit Argparse"""
    parser = argparse.ArgumentParser(
        description='Erzeugt Test-DXF-Dateien für verschiedene Testszenarien'
    )

    parser.add_argument(
        '--scene',
        type=str,
        required=True,
        help='Name der Testszene (z.B. Nummerierung1, Nummerierung2). Muss in der Config existieren.'
    )

    parser.add_argument(
        '--filename',
        type=str,
        default=None,
        help='Name der zu erzeugenden Testdatei (z.B. Nummerierung1.dxf). Falls nicht angegeben, wird scene + .dxf verwendet.'
    )

    parser.add_argument(
        '--output-dir',
        type=str,
        default=None,
        help='Ausgabeverzeichnis (Standard: testdata)'
    )

    parser.add_argument(
        '--config',
        type=str,
        default='create_tests.json',
        help='JSON-Konfigurationsdatei (Standard: create_tests.json)'
    )

    args = parser.parse_args()

    # Bestimme Filename: entweder angegeben oder aus scene ableiten
    if args.filename:
        filename = args.filename
    else:
        filename = args.scene + '.dxf'

    # Stelle sicher, dass Dateiname .dxf Endung hat
    if not filename.endswith('.dxf'):
        filename += '.dxf'

    # Generiere Testdaten
    generator = TestDataGenerator(filename, args.scene, config_file=args.config)

    if generator.generate():
        generator.save(args.output_dir)
        return 0
    else:
        print("Fehler bei der Generierung der Testdaten")
        return 1


if __name__ == '__main__':
    sys.exit(main())
