"""Zeichnet die Objektrahmen."""

import bpy
import os
import glob
import time
import math
import traceback

import gpu
import blf
from gpu_extras.batch import batch_for_shader
from bpy_extras.object_utils import world_to_camera_view
from bpy_extras import view3d_utils
from mathutils import Vector
from bpy.types import Panel, Operator, PropertyGroup, AddonPreferences
from bpy.props import (IntProperty, StringProperty, PointerProperty,
                       FloatProperty, BoolProperty, EnumProperty)

from . import state
from .colors import get_heatmap_color
from .grid_math import location_3d_to_region_2d
from .layout import oktagon


def draw_bbox_callback(context):
    """Zeichnet animierte 2D-Rahmen um Objekte - PREDATOR HUD Style"""
    try:
        current_time = time.time()
        state._bbox_animation_time = current_time
        
        scene = context.scene
        if not scene.basematerials_tracking:
            return
        
        view_layer = context.view_layer
        region = context.region
        rv3d = context.space_data.region_3d
        
        # FIXE PARAMETER
        use_heatmap = True  # Immer Heatmap
        mesh_only = True  # Nur Meshes
        
        # Objekte sammeln - Geometrie aus CACHE holen!
        geometry_counts = []
        valid_objects = []
        
        for obj in view_layer.objects:
            if not obj.visible_get():
                continue
            if mesh_only and obj.type != 'MESH':
                continue
            
            # Aus Cache holen
            if obj.name in state._cached_geometry_data:
                geo_count = state._cached_geometry_data[obj.name]['geo_count']
            else:
                # Nur bei neuen Objekten berechnen
                geo_count = 0
                tri_count = 0
                if obj.type == 'MESH' and obj.data:
                    geo_count = len(obj.data.vertices) + len(obj.data.edges) + len(obj.data.polygons)
                    for poly in obj.data.polygons:
                        tri_count += len(poly.vertices) - 2
                
                state._cached_geometry_data[obj.name] = {
                    'geo_count': geo_count,
                    'tri_count': tri_count
                }
            
            geometry_counts.append(geo_count)
            valid_objects.append(obj)
        
        # SEQUENZIELLE Animation initialisieren
        if not state._object_sequence or set([o.name for o in valid_objects]) != set(state._object_sequence):
            # Neue Objekt-Liste oder Änderung -> Sequenz neu aufbauen
            state._object_sequence = [obj.name for obj in valid_objects]
            state._sequence_index = 0
        
        # Sequenzielles Lock-On: Starte nächstes Objekt alle 0.2 Sekunden!
        time_since_start = current_time - state._animation_start_time
        current_sequence_index = int(time_since_start / 0.2)  # Alle 0.2s ein neues Objekt
        
        # Für jedes Objekt: Startzeit basierend auf Position in Sequenz
        for i, obj in enumerate(valid_objects):
            obj_index_in_sequence = state._object_sequence.index(obj.name) if obj.name in state._object_sequence else i
            
            # Animation startet wenn Sequenz-Index erreicht wird
            if obj.name not in state._object_animations:
                # Startzeit = animation_start + (index × 0.2 Sekunden)
                state._object_animations[obj.name] = state._animation_start_time + (obj_index_in_sequence * 0.2)
        
        if not valid_objects:
            return
        
        # Min/Max für Heatmap
        if use_heatmap and geometry_counts:
            min_geo = min(geometry_counts)
            max_geo = max(geometry_counts)
        else:
            min_geo, max_geo = 0, 1
        
        # Für 2D-Zeichnung vorbereiten
        gpu.state.blend_set('ALPHA')
        
        # FIXE PARAMETER
        alpha = 0.8  # Fixe Transparenz
        line_width = 2.0  # Fixe Linienbreite
        
        gpu.state.line_width_set(line_width)
        
        # Jedes Objekt zeichnen
        for i, obj in enumerate(valid_objects):
            # Bounding Box in 3D
            bbox_3d = [obj.matrix_world @ Vector(corner) for corner in obj.bound_box]
            
            # Alle 8 Ecken in 2D konvertieren
            bbox_2d = []
            all_visible = True
            
            for corner_3d in bbox_3d:
                corner_2d = location_3d_to_region_2d(region, rv3d, corner_3d)
                if corner_2d is None:
                    all_visible = False
                    break
                bbox_2d.append(corner_2d)
            
            if not all_visible:
                continue
            
            # Animation-Progress berechnen (0 -> 1 über 0.5 Sekunden!)
            obj_start_time = state._object_animations.get(obj.name, current_time)
            elapsed = current_time - obj_start_time
            anim_duration = 0.5  # 0.5 Sekunden Animation pro Objekt!
            
            # Objekt wird erst sichtbar wenn seine Zeit gekommen ist
            if elapsed < 0:
                # Noch nicht an der Reihe - nicht zeichnen
                continue
            
            if elapsed < anim_duration:
                # Linear progress (0 -> 1)
                linear_t = elapsed / anim_duration
                
                # EXTREME PARABEL: Exponential Ease-Out!
                # Exponential Ease-Out: 1 - e^(-6t)
                t = 1.0 - math.exp(-6 * linear_t)
            else:
                # Animation beendet: am Ziel
                t = 1.0
            
            # 2D Bounding Box berechnen (min/max der 2D-Punkte)
            min_x = min(p.x for p in bbox_2d)
            max_x = max(p.x for p in bbox_2d)
            min_y = min(p.y for p in bbox_2d)
            max_y = max(p.y for p in bbox_2d)
            
            center_x = (min_x + max_x) / 2
            center_y = (min_y + max_y) / 2
            width_2d = max_x - min_x
            height_2d = max_y - min_y
            
            # Start-Größe: größer (von außen)
            start_scale = 3.0
            end_scale = 1.0
            
            # Interpolierte Größe
            current_scale = start_scale + (end_scale - start_scale) * t
            
            # Skaliertes Rechteck berechnen
            half_w = (width_2d / 2) * current_scale
            half_h = (height_2d / 2) * current_scale
            
            # Die Form des Rahmens steht in hud/layout — dieselbe Quelle, aus
            # der sich auch die Beschriftungen ihre Ansatzpunkte holen. Die
            # Zahlen sind unveraendert: fester Eckenschnitt von 10 Pixeln,
            # Mindestmass 20 Pixel halbe Kantenlaenge.
            octagon_points = oktagon(center_x, center_y, half_w, half_h)

            # Farbe
            if use_heatmap:
                color = get_heatmap_color(geometry_counts[i], min_geo, max_geo)
            else:
                color = (1.0, 0.5, 0.0)  # Fallback Orange
            
            # KEINE Transparenz-Animation - volle Alpha!
            animated_alpha = alpha
            
            # Oktagon zeichnen
            shader = gpu.shader.from_builtin('POLYLINE_UNIFORM_COLOR')
            
            # Geschlossenes Oktagon
            line_coords = octagon_points + [octagon_points[0]]
            
            batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": line_coords})
            shader.bind()
            shader.uniform_float("lineWidth", line_width)
            shader.uniform_float("viewportSize", (region.width, region.height))
            shader.uniform_float("color", (*color, animated_alpha))
            batch.draw(shader)
        
        gpu.state.blend_set('NONE')
        
    except Exception as e:
        pass
