"""Nexo Scene Importer: schema-limited JSON import; no eval, scripts or remote access."""
bl_info = {"name": "Nexo Scene Importer", "author": "Nexo Lab", "version": (1, 0, 0), "blender": (3, 6, 0), "location": "File > Import > Nexo Scene", "category": "Import-Export"}
import json
import math
from pathlib import Path
import bpy
from bpy.props import StringProperty
from bpy_extras.io_utils import ImportHelper

def vector(value, size, default):
    if value is None:
        return default
    if not isinstance(value, list) or len(value) != size or any(type(n) not in (int, float) or not math.isfinite(n) or abs(n) > 10000 for n in value):
        raise ValueError("Vetor inválido na cena")
    return value

def validate(data):
    if not isinstance(data, dict) or data.get("version") != 1 or not isinstance(data.get("objects"), list):
        raise ValueError("Formato Nexo Scene inválido")
    if not 1 <= len(data["objects"]) <= 200:
        raise ValueError("Use entre 1 e 200 objetos")
    cleaned = []
    for item in data["objects"]:
        if not isinstance(item, dict) or item.get("type") not in ("cube", "sphere", "plane"):
            raise ValueError("Tipo de objeto não suportado")
        cleaned.append({"type": item["type"], "name": str(item.get("name", "Nexo"))[:80], "location": vector(item.get("location"), 3, [0,0,0]), "scale": vector(item.get("scale"), 3, [1,1,1]), "rotation": vector(item.get("rotation"), 3, [0,0,0]), "color": vector(item.get("color"), 4, [.5,.8,.3,1])})
    return cleaned

class NEXO_OT_import_scene(bpy.types.Operator, ImportHelper):
    bl_idname = "import_scene.nexo_json"
    bl_label = "Importar Nexo Scene"
    bl_options = {'REGISTER', 'UNDO'}
    filename_ext = ".json"
    filter_glob: StringProperty(default="*.json", options={'HIDDEN'})
    def execute(self, context):
        try:
            path = Path(self.filepath)
            if path.stat().st_size > 1024 * 1024:
                raise ValueError("Arquivo maior que 1 MB")
            items = validate(json.loads(path.read_text(encoding="utf-8")))
            collection = bpy.data.collections.new("Nexo Import")
            context.scene.collection.children.link(collection)
            for item in items:
                if item["type"] == "cube": bpy.ops.mesh.primitive_cube_add()
                elif item["type"] == "sphere": bpy.ops.mesh.primitive_uv_sphere_add()
                else: bpy.ops.mesh.primitive_plane_add()
                obj = context.object
                obj.name = item["name"]
                obj.location = item["location"]
                obj.scale = item["scale"]
                obj.rotation_euler = item["rotation"]
                for c in list(obj.users_collection): c.objects.unlink(obj)
                collection.objects.link(obj)
                material = bpy.data.materials.new(item["name"] + " material")
                material.diffuse_color = tuple(max(0, min(1, n)) for n in item["color"])
                obj.data.materials.append(material)
            self.report({'INFO'}, f"{len(items)} objetos importados")
            return {'FINISHED'}
        except Exception as exc:
            self.report({'ERROR'}, str(exc))
            return {'CANCELLED'}

def menu_import(self, context):
    self.layout.operator(NEXO_OT_import_scene.bl_idname, text="Nexo Scene (.json)")
def register():
    bpy.utils.register_class(NEXO_OT_import_scene)
    bpy.types.TOPBAR_MT_file_import.append(menu_import)
def unregister():
    bpy.types.TOPBAR_MT_file_import.remove(menu_import)
    bpy.utils.unregister_class(NEXO_OT_import_scene)
if __name__ == "__main__": register()
