import bpy
from .image_types import PROGRESSIVE_TEXTURE_SIZE_OPTIONS


_projectPathUpdatedCallbacks = []

def registerProjectPathUpdatedCallback(callback):
    _projectPathUpdatedCallbacks.append(callback)


def onProjectPathUpdated(self, context):
    for callback in _projectPathUpdatedCallbacks:
        try:
            callback(self, context)
        except Exception as e:
            print("Error in onProjectPathUpdated callback", e)
            pass
    pass


# this is registered on each scene
class NeedleMainSceneSettings(bpy.types.PropertyGroup):
    projectPath: bpy.props.StringProperty(name="Project Path", description="The path to the web project (or where the web project should be generated)", default="", subtype='DIR_PATH', update=onProjectPathUpdated)
    allowExtension: bpy.props.BoolProperty(name="Allow Extension", description="Disable to skip Needle addon extension hooks", default=True)
    mainScene: bpy.props.PointerProperty(type=bpy.types.Scene, name="", description="The main scene of the project. \n\nIf none is assigned the current scene will be exported. \nIf you have a scene assigned that scene will be exported regardless of which scene is currently active.")
    # this is currently progresssive textures
    useProgressive: bpy.props.BoolProperty(name="Use Progressive", description="Use progressive rendering", default=True)
    progressiveTextureSize: bpy.props.EnumProperty(name="Progressive Texture Size", description="This is the default size textures will be reduced to when using progressive texture", items=PROGRESSIVE_TEXTURE_SIZE_OPTIONS, default="128")
    useProgressiveMeshes: bpy.props.BoolProperty(name="Use Progressive Meshes", description="Use progressive meshes", default=True)
    exportOnSave: bpy.props.BoolProperty(name="Export On Save", description="Export the scene when saving the blend file", default=True)
    compressOnSave: bpy.props.BoolProperty(name="Compress On Save", description="Compress and generate progressive assets after export - this is useful to preview a production build", default=False)
    useGzip: bpy.props.BoolProperty(name="Use Gzip Compression", description="Use gzip compression. If you deploy to your own webserver you need to make sure it does support serving .gz compressed files. Gzip compression generally reduces the size of your build by a fair amount so we recommend turning it on where possible (e.g. when deploying to Glitch it should be turned on)", default=False)
    useRapier: bpy.props.BoolProperty(name="Use Physics Engine", description="Enable to include the physics library. If set to False physics will be stripped which will reduce the size of your website", default=False)
    
    # needle menu settings
    showNeedleMenu: bpy.props.BoolProperty(name="Show Needle Menu", description="Show the Needle menu", default=True)
    showNeedleMenuLogo: bpy.props.BoolProperty(name="Needle Logo", description="Show the Needle Logo in menu - this requires a Needle Engine license to be configured", default=True)
    showQRCodeButton: bpy.props.BoolProperty(name="QR Code Button", description="Show the QR code button in the Needle menu", default=True)
    showMuteButton: bpy.props.BoolProperty(name="Mute Button", description="Show a mute (audio) button in the Needle menu", default=False)
    showFullscreenButton: bpy.props.BoolProperty(name="Fullscreen Button", description="Show a fullscreen button in the Needle menu", default=False)

    # Animation
    nlatracks: bpy.props.BoolProperty(name="NLA Tracks", description="Automatically export nla track animation as a Timeline. The timeline will automatically play in the web", default=True)

    # XR
    vr: bpy.props.BoolProperty(name="VR (immersive-vr)", description="Enable to add VR support to your scene (for more control add a WebXR component)", default=True)
    ar: bpy.props.BoolProperty(name="AR (immersive-ar)", description="Enable to add AR support to your scene (for more control add a WebXR component)", default=True)
    quicklook: bpy.props.BoolProperty(name="QuickLook (iOS)", description="Enable to add runtime QuickLook (USDZ) export to your scene for iOS AR support using Quicklook", default=True)
    arScale: bpy.props.FloatProperty(name="AR Scale", description="The scale of the scene in AR", default=1.0, min=0.1, max=10.0)
    depthSensing: bpy.props.BoolProperty(name="Depth Sensing", description="Enable depth sensing (in passthrough AR. For example on Meta Quest in AR mode)", default=True)

    # Networking
    useNetworking: bpy.props.BoolProperty(name="Use Networking", description="Enable networking features", default=True)
    voip: bpy.props.BoolProperty(name="Voice Chat", description="Enable voice over IP / voice chat (requires networking to be enabled)", default=True)

    # rendering settings
    orbitControls: bpy.props.BoolProperty(name="Orbit Controls", description="When enabled a OrbitControls component will automatically added to your camera on export", default=True)
    autoFit: bpy.props.BoolProperty(name="Auto Fit", description="Automatically fit the camera to the scene", default=True)
    contactShadows: bpy.props.BoolProperty(name="Contact Shadows", description="Enable contact shadows", default=True)
    contactShadowsDarkness: bpy.props.FloatProperty(name="Darkness", description="The darkness of the contact shadows", default=0.5, min=0.0, max=2.0)
    groundProjection: bpy.props.BoolProperty(name="Ground Projection", description="Projects the environment skybox to simulate a ground", default=False)
    groundProjectionHeight: bpy.props.FloatProperty(name="Camera Height", description="How far the camera that took the photo was above the ground. A larger value will magnify the downward part of the image.", default=3.0)

    remoteSkybox: bpy.props.BoolProperty(name="Remote Skybox", description="Enable a remote skybox component. This allowes you to drop HDRi/EXR textures into the browser to load", default=False)
    dropListener: bpy.props.BoolProperty(name="Drop Listener", description="Enable a drop listener component. This allows you to drop models or glTF/GLB model urls in the browser to load", default=False)

def register():
    bpy.utils.unregister_class(NeedleMainSceneSettings) # < might be because of the auto reload plugin
    bpy.utils.register_class(NeedleMainSceneSettings)
    bpy.types.Scene.needle_blend_settings = bpy.props.PointerProperty(type=NeedleMainSceneSettings)
    pass

def unregister():
    bpy.utils.unregister_class(NeedleMainSceneSettings)
    del bpy.types.Scene.needle_blend_settings
    pass

def tryGetMainSceneSettings() -> NeedleMainSceneSettings | None:
    try:
        scenes = bpy.data.scenes
        # first try to find a scene that has a main scene assigned
        for scene in scenes:
            if scene.needle_blend_settings is not None and scene.needle_blend_settings.mainScene is not None:
                return scene.needle_blend_settings
        # then try to find a scene that has a project path assigned
        import os
        for scene in scenes:
            if scene.needle_blend_settings is not None and scene.needle_blend_settings.projectPath is not None:
                # then check if the project path is valid and exists
                path = scene.needle_blend_settings.projectPath
                if path is not None and len(path) > 0:
                    path = bpy.path.abspath(path)
                    if os.path.exists(path):
                        return scene.needle_blend_settings
        # fallback to current scene
        return bpy.context.scene.needle_blend_settings
    except:
        return None


def tryFindMainScene() -> bpy.types.Scene | None:
    try:
        return tryGetMainSceneSettings().mainScene
    except:
        return None