# Addon metadata - MUST be at module level for Blender discovery
# IMPORTANT: bl_info must contain ONLY literal values (no expressions/conditionals)
# for ast.literal_eval() to parse it during addon discovery
bl_info = {
    "name": "Text Texture Generator Pro",
    "author": "Marc Mintel <marc@mintel.me>",
    "version": (1, 2, 5),
    "blender": (4, 0, 0),
    "location": "3D View > Sidebar (N) > Tool Tab | Shader Editor > Sidebar > Tool Tab",
    "description": "Generate image textures from text with accurate dimensions and powerful styling options",
    "category": "Material",
}

import sys, os, platform
_platform = platform.system().lower()
_lib_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), f"lib-{_platform}")

# Only use bundled libs if they completely work for this Python version
if os.path.exists(_lib_dir) and _lib_dir not in sys.path:
    sys.path.insert(0, _lib_dir)
    try:
        import PIL.Image
    except ImportError:
        # Bundled library doesn't match this python version (e.g. Blender 5)
        sys.path.remove(_lib_dir)
        # Clear any half-initialized PIL modules from the cache
        keys_to_remove = [k for k in sys.modules if k == 'PIL' or k.startswith('PIL.')]
        for k in keys_to_remove:
            del sys.modules[k]

import bpy
import bmesh
from bpy.types import Operator, Panel, PropertyGroup, UIList
from bpy.props import StringProperty, IntProperty, FloatVectorProperty, FloatProperty, BoolProperty, EnumProperty, CollectionProperty, PointerProperty
import tempfile
import subprocess
import json
import time

# Import utility functions
from .utils import install_pillow, get_system_fonts, get_font_enum_items, log_addon_configuration

# Import preset system functions (conditionally for free version)
try:
    from .presets import (
        initialize_presets,
        refresh_presets,
        refresh_presets_sync,
        ensure_presets_available,
        migrate_presets_if_needed
    )
    PRESETS_AVAILABLE = True
except ImportError:
    # Free version - no presets functionality
    PRESETS_AVAILABLE = False
    def initialize_presets():
        """Mock function for free version"""
        pass
    def refresh_presets():
        """Mock function for free version"""
        pass
    def refresh_presets_sync():
        """Mock function for free version"""
        return True
    def ensure_presets_available():
        """Mock function for free version"""
        return True
    def migrate_presets_if_needed():
        """Mock function for free version"""
        return {'migrated_count': 0}

# Import core generation functions
from .core import generate_texture_image, generate_preview

# Import property groups
from .properties import (
    TEXT_TEXTURE_ImageOverlay,
    TEXT_TEXTURE_Preset,
    TEXT_TEXTURE_Properties
)

# Define MockOperator once at module level for all conditional imports
class MockOperator:
    """Mock operator for features not available in free version"""
    bl_idname = ""
    bl_label = ""
    bl_description = ""
    def execute(self, context):
        return {'CANCELLED'}

# Import operators - generation operators are always available
from .operators import (
    TEXT_TEXTURE_OT_generate,
    TEXT_TEXTURE_OT_preview,
    TEXT_TEXTURE_OT_generate_shader,
    TEXT_TEXTURE_OT_generate_plane,
    TEXT_TEXTURE_OT_reset_settings,
)

# Try to import utility operators (might not be available in free version)
try:
    from .operators import (
        TEXT_TEXTURE_OT_refresh_preview,
        TEXT_TEXTURE_OT_view_preview_zoom,
        TEXT_TEXTURE_OT_add_overlay,
        TEXT_TEXTURE_OT_remove_overlay,
        TEXT_TEXTURE_OT_duplicate_overlay,
        TEXT_TEXTURE_OT_delete_overlay,
        TEXT_TEXTURE_OT_move_overlay,
        TEXT_TEXTURE_OT_open_panel,
        TEXT_TEXTURE_OT_refresh_fonts,
        TEXT_TEXTURE_OT_set_anchor_point,
        TEXT_TEXTURE_OT_sync_margins,
        TEXT_TEXTURE_OT_recover_data,
    )
    UTILITY_OPERATORS_AVAILABLE = True
except ImportError:
    # Free version - use mock operators for utility functionality
    UTILITY_OPERATORS_AVAILABLE = False
    TEXT_TEXTURE_OT_refresh_preview = MockOperator
    TEXT_TEXTURE_OT_view_preview_zoom = MockOperator
    TEXT_TEXTURE_OT_add_overlay = MockOperator
    TEXT_TEXTURE_OT_remove_overlay = MockOperator
    TEXT_TEXTURE_OT_duplicate_overlay = MockOperator
    TEXT_TEXTURE_OT_delete_overlay = MockOperator
    TEXT_TEXTURE_OT_move_overlay = MockOperator
    TEXT_TEXTURE_OT_open_panel = MockOperator
    TEXT_TEXTURE_OT_refresh_fonts = MockOperator
    TEXT_TEXTURE_OT_set_anchor_point = MockOperator
    TEXT_TEXTURE_OT_sync_margins = MockOperator
    TEXT_TEXTURE_OT_recover_data = MockOperator

# Conditionally import preset-related operators
if PRESETS_AVAILABLE:
    from .operators import (
        TEXT_TEXTURE_OT_save_preset,
        TEXT_TEXTURE_OT_save_preset_enter,
        TEXT_TEXTURE_OT_load_preset,
        TEXT_TEXTURE_OT_delete_preset,
        TEXT_TEXTURE_OT_refresh_presets,
        TEXT_TEXTURE_OT_export_presets,
        TEXT_TEXTURE_OT_import_presets
    )
else:
    # Use mock classes for free version
    TEXT_TEXTURE_OT_save_preset = MockOperator
    TEXT_TEXTURE_OT_save_preset_enter = MockOperator
    TEXT_TEXTURE_OT_load_preset = MockOperator
    TEXT_TEXTURE_OT_delete_preset = MockOperator
    TEXT_TEXTURE_OT_refresh_presets = MockOperator
    TEXT_TEXTURE_OT_export_presets = MockOperator
    TEXT_TEXTURE_OT_import_presets = MockOperator

# Text editor operators removed - feature deprecated
TEXT_EDITOR_OPERATORS_AVAILABLE = False

# Import UI panels and functions
from .ui import (
    TEXT_TEXTURE_PT_panel,
    TEXT_TEXTURE_PT_panel_3d,
    TEXT_TEXTURE_PT_panel_properties,
    menu_func_node_editor,
    menu_func_view3d,
    menu_func_image
)

# ============================================================================
# REGISTRATION
# ============================================================================

# Global list to track successfully registered classes
_registered_classes = []

classes = (
    TEXT_TEXTURE_ImageOverlay,
    TEXT_TEXTURE_Preset,
    TEXT_TEXTURE_Properties,
    TEXT_TEXTURE_OT_generate,
    TEXT_TEXTURE_OT_preview,
    TEXT_TEXTURE_OT_generate_shader,
    TEXT_TEXTURE_OT_generate_plane,
    TEXT_TEXTURE_OT_reset_settings,
    TEXT_TEXTURE_OT_refresh_preview,
    TEXT_TEXTURE_OT_view_preview_zoom,
    TEXT_TEXTURE_OT_add_overlay,
    TEXT_TEXTURE_OT_remove_overlay,
    TEXT_TEXTURE_OT_duplicate_overlay,
    TEXT_TEXTURE_OT_delete_overlay,
    TEXT_TEXTURE_OT_move_overlay,
    TEXT_TEXTURE_OT_open_panel,
    TEXT_TEXTURE_OT_save_preset,
    TEXT_TEXTURE_OT_save_preset_enter,
    TEXT_TEXTURE_OT_set_anchor_point,
    TEXT_TEXTURE_OT_sync_margins,
    TEXT_TEXTURE_OT_load_preset,
    TEXT_TEXTURE_OT_delete_preset,
    TEXT_TEXTURE_OT_refresh_fonts,
    TEXT_TEXTURE_OT_refresh_presets,
    TEXT_TEXTURE_OT_export_presets,
    TEXT_TEXTURE_OT_import_presets,
    TEXT_TEXTURE_OT_recover_data,
    TEXT_TEXTURE_PT_panel,
    TEXT_TEXTURE_PT_panel_3d,
    TEXT_TEXTURE_PT_panel_properties,
)

def _is_mock_class(cls):
    """Check if a class is a mock operator (not a real Blender class)."""
    # Mock classes don't inherit from Blender's base classes and lack bl_rna
    return (
        not hasattr(cls, 'bl_rna') and
        hasattr(cls, 'bl_idname') and
        cls.bl_idname == "" and
        hasattr(cls, 'execute') and
        cls.__name__ == 'MockOperator'
    )

def register():
    # Ensure Pillow is installed
    try:
        import PIL
    except ImportError:
        try:
            install_pillow()
        except Exception as e:
            print(f"Text Texture Generator: Failed to install Pillow: {e}")

    # Clear the registered classes list
    global _registered_classes
    _registered_classes.clear()
    
    for cls in classes:
        # Skip mock classes - they can't be registered as Blender classes
        if _is_mock_class(cls):
            continue
            
        try:
            bpy.utils.register_class(cls)
            _registered_classes.append(cls)
        except Exception as e:
            print(f"Failed to register {cls.__name__}: {e}")
            # Continue with other classes even if one fails
    
    bpy.types.Scene.text_texture_props = PointerProperty(type=TEXT_TEXTURE_Properties)
    
    # CRITICAL FIX: Force UI refresh after registration
    try:
        # Update all areas to ensure panels are properly displayed
        for window in bpy.context.window_manager.windows:
            for area in window.screen.areas:
                area.tag_redraw()
    except Exception as e:
        print(f"UI refresh failed: {e}")
    
    # Add to menus
    bpy.types.NODE_MT_add.append(menu_func_node_editor)
    bpy.types.VIEW3D_MT_add.append(menu_func_view3d)
    bpy.types.VIEW3D_MT_mesh_add.append(menu_func_view3d)
    bpy.types.NODE_MT_node.append(menu_func_node_editor)
    
    # Add to Image menu if available
    if hasattr(bpy.types, 'IMAGE_MT_image'):
        bpy.types.IMAGE_MT_image.append(menu_func_image)
    
    # Initialize presets using reliable synchronization - no timer chains needed
    
    # Use the new reliable initialization system
    try:
        # Perform migration check first
        migration_result = migrate_presets_if_needed()
        if migration_result['migrated_count'] > 0:
            print(f"Migrated {migration_result['migrated_count']} presets during registration")
        
        # Initialize presets using the simplified system
        initialize_presets()
        print("Preset initialization completed successfully")
        
    except Exception as e:
        print(f"Error during preset initialization: {e}")
        # Don't fail registration if preset initialization fails
        import traceback
        traceback.print_exc()
    
    # Add handler to reload presets when blend file changes
    @bpy.app.handlers.persistent
    def on_file_load(dummy):
        """Reload presets when a blend file is loaded"""
        try:
            print("Reloading presets after file load...")
            
            # Use reliable synchronous refresh instead of timer
            success = refresh_presets_sync()
            if success:
                print("Presets reloaded successfully after file load")
            else:
                print("Warning: Preset reload failed after file load")
                
        except Exception as e:
            print(f"Error reloading presets: {e}")
            import traceback
            traceback.print_exc()
            
        # AUTO-MIGRATION: Scan for orphaned text automatically on file load!
        def _trigger_scan():
            if hasattr(bpy.context, 'scene'):
                try:
                    # Execute quietly without user interaction
                    bpy.ops.text_texture.recover_data('EXEC_DEFAULT', quiet=True)
                except Exception as op_err:
                    print(f"DEBUG: Auto-scan failed/skipped: {op_err}")
            return None
            
        print("Registering auto-migration scan timer...")
        if hasattr(bpy.app.timers, 'register'):
            bpy.app.timers.register(_trigger_scan, first_interval=1.5)
        else:
            _trigger_scan()
    
    # Register the file load handler
    if on_file_load not in bpy.app.handlers.load_post:
        bpy.app.handlers.load_post.append(on_file_load)
        
    # Log the addon configuration at the end of registration
    try:
        log_addon_configuration()
    except Exception as e:
        print(f"Logging configuration failed: {e}")
    

def unregister():
    # Clean up preview
    try:
        if bpy.context.scene:
            props = bpy.context.scene.text_texture_props
            if props and props.preview_image:
                bpy.data.images.remove(props.preview_image)
    except Exception:
        pass
    
    if "TextTexturePreview" in bpy.data.images:
        bpy.data.images.remove(bpy.data.images["TextTexturePreview"])
    
    # Remove file load handler
    try:
        for handler in bpy.app.handlers.load_post[:]:
            if handler.__name__ == 'on_file_load' and 'TTG' in str(handler):
                bpy.app.handlers.load_post.remove(handler)
    except Exception as e:
        print(f"Error removing file load handler: {e}")
    
    # Remove from menus
    bpy.types.NODE_MT_add.remove(menu_func_node_editor)
    bpy.types.VIEW3D_MT_add.remove(menu_func_view3d)
    bpy.types.VIEW3D_MT_mesh_add.remove(menu_func_view3d)
    bpy.types.NODE_MT_node.remove(menu_func_node_editor)
    
    if hasattr(bpy.types, 'IMAGE_MT_image'):
        bpy.types.IMAGE_MT_image.remove(menu_func_image)
    
    # Only unregister classes that were successfully registered
    
    for cls in reversed(_registered_classes):
        try:
            bpy.utils.unregister_class(cls)
        except Exception as e:
            print(f"Failed to unregister {cls.__name__}: {e}")
            # Continue with other classes even if one fails
    
    # Clear the registered classes list
    _registered_classes.clear()
    
    del bpy.types.Scene.text_texture_props

if __name__ == "__main__":
    register()
