import bpy
import os
import json
import time
import platform

# ============================================================================
# PRESET STORAGE SYSTEM - V3.0 (SIMPLIFIED TWO-TIER)
# ============================================================================
#
# The Text Texture Generator uses a SIMPLIFIED TWO-TIER preset storage system:
#
# 1. PERSISTENT FILE STORAGE (Default)
#    - Survives addon updates and Blender upgrades
#    - Stored in Blender's user config directory
#    - Shared across all blend files
#    - Default behavior when checkbox is unchecked
#
# 2. BLEND FILE STORAGE (Optional)
#    - Presets travel with the .blend file
#    - Perfect for project-specific presets
#    - Stored in scene custom properties
#    - Used when "Save with .blend file" checkbox is checked
#
# PRIORITY SYSTEM:
# - Blend file presets ALWAYS take priority over persistent ones
# - Name conflicts show only the blend file version
#
# MIGRATION SYSTEM:
# - Automatically migrates LOCAL_FILE presets to PERSISTENT_FILE storage
# - Creates backups before migration
# - One-time process with safety checks
#
# ============================================================================

def get_preset_path():
    pass
    """Get path for storing presets (legacy local storage)
    
    LEGACY SYSTEM: This storage location is vulnerable to addon updates.
    Presets stored here will be lost when the addon is updated through
    Blender's Add-ons preferences. This function is maintained for
    backward compatibility only.
    
    For new installations, use get_persistent_preset_path() instead.
    """
    addon_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
    presets_dir = os.path.join(addon_dir, "presets")
    if not os.path.exists(presets_dir):
        pass
        try:
            pass
            os.makedirs(presets_dir)
        except OSError as e:
            pass
            print(f"Error creating presets directory: {e}")
    return presets_dir

def get_persistent_preset_path():
    pass
    """Get persistent path for storing presets (survives addon updates)"""
    import bpy
    
    # Get Blender's user config directory
    config_dir = bpy.utils.user_resource('CONFIG')
    if not config_dir:
        pass
        # Fallback to addon directory if config path unavailable
        return get_preset_path()
    
    # Create addon-specific subdirectory
    persistent_dir = os.path.join(config_dir, "text_texture_generator", "presets")
    
    try:
        pass
        if not os.path.exists(persistent_dir):
            pass
            os.makedirs(persistent_dir, exist_ok=True)
        return persistent_dir
    except OSError as e:
        pass
        # Fallback to addon directory
        return get_preset_path()

def get_addon_version():
    pass
    """Get current addon version for migration tracking"""
    # Import bl_info from the main addon file
    import sys
    import importlib.util
    
    # Get the main addon module
    main_module_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
    init_file = os.path.join(main_module_path, "__init__.py")
    
    try:
        pass
        spec = importlib.util.spec_from_file_location("main_addon", init_file)
        main_addon = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(main_addon)
        return main_addon.bl_info["version"]
    except Exception as e:
        pass
        return (2, 3, 2)  # Fallback version

def get_version_file_path():
    pass
    """Get path to version tracking file"""
    persistent_dir = os.path.dirname(get_persistent_preset_path())
    return os.path.join(persistent_dir, "addon_version.json")

def get_stored_version():
    pass
    """Get previously stored addon version"""
    version_file = get_version_file_path()
    try:
        pass
        if os.path.exists(version_file):
            pass
            with open(version_file, 'r') as f:
                data = json.load(f)
                return tuple(data.get('version', (0, 0, 0)))
    except (json.JSONDecodeError, OSError) as e:
        pass
        print(f"Error reading version file: {e}")
    return (0, 0, 0)

def save_current_version():
    pass
    """Save current addon version to persistent storage"""
    version_file = get_version_file_path()
    try:
        pass
        version_data = {
            'version': get_addon_version(),
            'timestamp': time.time()
        }
        with open(version_file, 'w') as f:
            json.dump(version_data, f, indent=2)
    except (OSError, json.JSONEncodeError) as e:
        pass
        print(f"Error saving version file: {e}")

def get_blend_file_presets():
    pass
    """Get presets stored in the current blend file"""
    try:
        pass
        # Get custom properties from the scene
        import bpy
        scene = bpy.context.scene
        
        # DETAILED LOGGING: Function entry
        
        # Store presets in scene custom properties
        if "text_texture_presets" not in scene:
            pass
            scene["text_texture_presets"] = "{}"
        else:
            pass
            print("Found 'text_texture_presets' in scene")
        
        preset_data = scene.get("text_texture_presets", "{}")
        
        if isinstance(preset_data, str):
            pass
            try:
                pass
                import json
                parsed_presets = json.loads(preset_data)
                
                if isinstance(parsed_presets, dict):
                    pass
                    print(f"Parsed presets count: {len(parsed_presets)}")
                    
                    # DETAILED VERIFICATION: Check shader properties in each preset
                    for preset_name, preset_content in parsed_presets.items():
                        pass
                        if isinstance(preset_content, dict):
                            pass
                            print(f"Preset '{preset_name}' is valid")
                        else:
                            pass
                            print(f"Preset '{preset_name}' is not a dict")
                
                return parsed_presets
                
            except json.JSONDecodeError as json_err:
                pass
                print("Error parsing blend file presets, resetting to empty")
                scene["text_texture_presets"] = "{}"
                return {}
        else:
            pass
            return {}
    except Exception as e:
        pass
        import traceback
        print(f"Error getting blend file presets: {e}")
        return {}

def save_blend_file_preset(preset_name, preset_data):
    """Save a preset to the current blend file"""
    try:
        print(f"DEBUG: save_blend_file_preset - Name: '{preset_name}'")
        import bpy
        import json
        scene = bpy.context.scene
        
        # DETAILED LOGGING: Function entry
        if isinstance(preset_data, dict):
            print(f"DEBUG: Preset keys to save: {list(preset_data.keys())}")
        else:
            print("DEBUG ERROR: preset_data is not a dictionary!")
        
        # Get existing presets
        presets = get_blend_file_presets()
        
        # Add or update the preset
        presets[preset_name] = preset_data
        
        # VERIFY: Check that shader properties are in the preset we're about to save
        if preset_name in presets and isinstance(presets[preset_name], dict):
            pass
            saved_preset = presets[preset_name]
            print(f"Verified preset saved successfully")
        
        # Save back to scene custom properties
        json_data = json.dumps(presets, indent=2)
        
        scene["text_texture_presets"] = json_data
        
        # FINAL VERIFICATION: Read back from scene to confirm save
        readback_data = scene.get("text_texture_presets", "{}")
        if readback_data:
            pass
            try:
                pass
                readback_presets = json.loads(readback_data)
                if preset_name in readback_presets:
                    pass
                    readback_preset = readback_presets[preset_name]
                    print(f"Readback verification successful")
                else:
                    pass
                    print(f"ERROR: Preset '{preset_name}' not found in readback data!")
            except json.JSONDecodeError as json_err:
                pass
                print(f"ERROR: Could not parse readback JSON: {json_err}")
        else:
            pass
            print(f"ERROR: No data in scene['text_texture_presets'] after save!")
        
        print(f"Saved preset '{preset_name}' to blend file")
        return True
    except Exception as e:
        pass
        import traceback
        print(f"Error saving preset to blend file: {e}")
        return False

def delete_blend_file_preset(preset_name):
    """Delete a preset from the current blend file"""
    try:
        print(f"DEBUG: delete_blend_file_preset - Name: '{preset_name}'")
        import bpy
        import json
        scene = bpy.context.scene
        
        # Get existing presets
        presets = get_blend_file_presets()
        
        # Remove the preset if it exists
        if preset_name in presets:
            del presets[preset_name]
            scene["text_texture_presets"] = json.dumps(presets, indent=2)
            print(f"DEBUG: Successfully deleted preset '{preset_name}' from blend file")
            return True
        else:
            print(f"DEBUG: Preset '{preset_name}' not found in blend file for deletion")
            return False
    except Exception as e:
        print(f"DEBUG ERROR deleting preset from blend file: {e}")
        return False

def migrate_from_legacy_system():
    pass
    """
    One-time migration from old three-tier system to simplified two-tier system.
    Moves LOCAL_FILE presets to PERSISTENT_FILE and creates backup.
    """
    try:
        pass
        legacy_dir = get_preset_path()
        persistent_dir = get_persistent_preset_path()
        
        # Check if legacy directory exists and is different from persistent
        if not os.path.exists(legacy_dir) or legacy_dir == persistent_dir:
            pass
            return True
            
        # Check for migration marker file to avoid duplicate migrations
        migration_marker = os.path.join(persistent_dir, ".migration_complete")
        if os.path.exists(migration_marker):
            pass
            return True
            
        # Find legacy preset files
        legacy_files = []
        for filename in os.listdir(legacy_dir):
            pass
            if filename.endswith('.json'):
                pass
                legacy_files.append(filename)
        
        if not legacy_files:
            pass
            # Create marker even if no files to migrate
            with open(migration_marker, 'w') as f:
                f.write("Migration completed - no legacy presets found")
            return True
            
        
        # Create backup directory in persistent location
        backup_dir = os.path.join(persistent_dir, "legacy_backup")
        os.makedirs(backup_dir, exist_ok=True)
        
        # Load existing persistent presets to avoid conflicts
        existing_persistent = set()
        if os.path.exists(persistent_dir):
            pass
            for filename in os.listdir(persistent_dir):
                pass
                if filename.endswith('.json'):
                    pass
                    existing_persistent.add(filename)
        
        migrated_count = 0
        skipped_count = 0
        
        # Migrate each legacy preset
        for filename in legacy_files:
            pass
            preset_name = os.path.splitext(filename)[0]
            legacy_file = os.path.join(legacy_dir, filename)
            persistent_file = os.path.join(persistent_dir, filename)
            backup_file = os.path.join(backup_dir, filename)
            
            try:
                pass
                # Create backup copy first
                import shutil
                shutil.copy2(legacy_file, backup_file)
                
                # If preset doesn't exist in persistent storage, migrate it
                if filename not in existing_persistent:
                    pass
                    shutil.copy2(legacy_file, persistent_file)
                    migrated_count += 1
                else:
                    pass
                    skipped_count += 1
                    
            except Exception as e:
                pass
                print(f"Error migrating preset '{preset_name}': {e}")
        
        print(f"Migration completed: {migrated_count} migrated, {skipped_count} skipped")
        
        # Create migration completion marker
        with open(migration_marker, 'w') as f:
            migration_info = {
                "migration_date": time.time(),
                "migrated_count": migrated_count,
                "skipped_count": skipped_count,
                "backup_location": backup_dir
            }
            import json
            json.dump(migration_info, f, indent=2)
        
        return True
        
    except Exception as e:
        pass
        return False

def get_unified_preset_list():
    pass
    """
    Get unified preset list with two-tier loading and priority rules.
    Returns dict with preset names as keys and (preset_data, source) as values.
    
    Priority order: BLEND_FILE > PERSISTENT_FILE
    Blend file presets always take priority over persistent ones.
    """
    all_presets = {}
    
    try:
        pass
        # Load persistent presets first (lower priority)
        persistent_dir = get_persistent_preset_path()
        if os.path.exists(persistent_dir):
            pass
            for filename in os.listdir(persistent_dir):
                pass
                if filename.endswith('.json') and not filename.startswith('.'):
                    pass
                    preset_name = os.path.splitext(filename)[0]
                    try:
                        pass
                        with open(os.path.join(persistent_dir, filename), 'r') as f:
                            preset_data = json.load(f)
                        all_presets[preset_name] = (preset_data, 'PERSISTENT_FILE')
                    except (json.JSONDecodeError, OSError) as e:
                        pass
                        print(f"Error reading persistent preset {preset_name}: {e}")
        
        # Load blend file presets and override any conflicts (higher priority)
        blend_presets = get_blend_file_presets()
        for name, data in blend_presets.items():
            pass
            all_presets[name] = (data, 'BLEND_FILE')
            
    except Exception as e:
        print(f"DEBUG: Error in get_unified_preset_list: {e}")
    
    print(f"DEBUG: get_unified_preset_list returning {len(all_presets)} presets")
    return all_presets

def save_preset_unified(preset_data, name, save_to_blend_file=False):
    """
    Save a preset to either persistent file or blend file based on user choice.
    Default behavior saves to persistent file.
    Always cleans up the alternative location to prevent shadowing/duplication.
    """
    print(f"DEBUG: save_preset_unified - Name: '{name}', SaveToBlend: {save_to_blend_file}")
    
    # Deep data log
    import json
    try:
        data_dump = json.dumps(preset_data, indent=2)
        print(f"DEBUG: FULL PRESET DATA PAYLOAD:\n{data_dump}")
    except Exception as e:
        print(f"DEBUG: Error dumping preset_data: {e}")
    
    if save_to_blend_file:
        print(f"DEBUG: Saving to Blend File: {name}")
        success = save_blend_file_preset(name, preset_data)
        
        # Clean up from persistent storage to avoid duplication
        try:
            persistent_dir = get_persistent_preset_path()
            persistent_file = os.path.join(persistent_dir, f"{name}.json")
            if os.path.exists(persistent_file):
                print(f"DEBUG: Removing shadowed persistent file: {persistent_file}")
                os.remove(persistent_file)
        except Exception as e:
            print(f"DEBUG: Error removing shadowed persistent preset: {e}")
            
        return success
    else:
        print(f"DEBUG: Saving to Persistent Storage: {name}")
        # Clean up from blend file to avoid it shadowing the new persistent one
        try:
            print(f"DEBUG: Attempting to delete from blend file if exists: {name}")
            delete_blend_file_preset(name)
        except Exception as e:
            print(f"DEBUG: Error removing shadowed blend preset: {e}")
            
        # Save to persistent file
        try:
            pass
            persistent_dir = get_persistent_preset_path()
            persistent_file = os.path.join(persistent_dir, f"{name}.json")
            
            with open(persistent_file, 'w') as f:
                json.dump(preset_data, f, indent=2)
            
            return True
            
        except Exception as e:
            pass
            print(f"Error saving preset to persistent storage: {e}")
            return False

def initialize_presets():
    pass
    """Initialize the simplified preset system and run migration if needed."""
    try:
        pass
        import bpy
        if not hasattr(bpy.context, 'scene') or not bpy.context.scene:
            pass
            return
        
        props = bpy.context.scene.text_texture_props
        if not props:
            pass
            return
        
        
        print("Starting preset initialization...")
        
        # Run one-time migration from old system
        migrate_from_legacy_system()
        
        # Clear existing presets to avoid duplicates
        props.presets.clear()
        
        # Get unified preset list
        all_presets = get_unified_preset_list()
        
        # Add all presets to UI list
        for preset_name, (preset_data, source) in all_presets.items():
            pass
            preset = props.presets.add()
            preset.name = preset_name
            preset.source = source
        
        # Report results
        blend_count = len([p for p in props.presets if p.source == 'BLEND_FILE'])
        persistent_count = len([p for p in props.presets if p.source == 'PERSISTENT_FILE'])
        
        
        print(f"Initialized {len(props.presets)} presets ({blend_count} blend file, {persistent_count} persistent)")
        
    except Exception as e:
        pass
        print(f"Critical error in initialize_presets: {e}")
        import traceback
        traceback.print_exc()

def refresh_presets():
    pass
    """Refresh the preset list by rescanning files (legacy function)"""
    import bpy
    refresh_presets_sync()
    
    # Force UI update
    try:
        pass
        if bpy.context.area:
            pass
            bpy.context.area.tag_redraw()
    except:
        pass
        pass

def refresh_presets_sync():
    pass
    """Centralized, synchronous preset refresh - guarantees completion"""
    try:
        pass
        import bpy
        
        
        print("Synchronizing presets...")
        
        # Ensure we have valid context
        if not hasattr(bpy.context, 'scene') or not bpy.context.scene:
            pass
            return False
        
        props = bpy.context.scene.text_texture_props
        if not props:
            pass
            return False
        
        # Run the simplified initialization
        initialize_presets()
        
        # Validate that presets are actually loaded
        preset_count = len(props.presets)
        if preset_count == 0:
            pass
            print("Warning: No presets found after refresh")
        else:
            pass
            print(f"Preset sync complete - {preset_count} presets available")
        
        return True
        
    except Exception as e:
        pass
        import traceback
        traceback.print_exc()
        return False

def ensure_presets_available():
    pass
    """Defensive programming - ensure presets are loaded before UI operations"""
    try:
        pass
        import bpy
        
        if not hasattr(bpy.context, 'scene') or not bpy.context.scene:
            pass
            return False
            
        props = bpy.context.scene.text_texture_props
        if not props:
            pass
            return False
            
        # If no presets loaded, try to load them
        if len(props.presets) == 0:
            pass
            print("No presets available - attempting to load...")
            return refresh_presets_sync()
        
        return True
        
    except Exception as e:
        pass
        print(f"Error in ensure_presets_available: {e}")
        return False