# Generated by Copilot
# Maintained by Dinesh Kumar C (https://github.com/Dinesh210805/blender-mcp)
# Forked from original work by Siddharth Ahuja (https://github.com/ahujasid/blender-mcp)

"""Scene and object management tools for Blender MCP."""

import json
import tempfile
import os
from typing import Optional
from pathlib import Path

from mcp.server.fastmcp import Context, Image

from .base import BaseTool, tool_wrapper
from ..utils import validate_object_name, validate_code_safety, validate_file_path
from ..exceptions import ValidationError, SecurityError
from ..config import config


class SceneInfoTool(BaseTool):
    """Get information about the current Blender scene."""
    
    @tool_wrapper
    def execute(self) -> str:
        """Get detailed information about the current Blender scene."""
        result = self.send_command("get_scene_info")
        return json.dumps(result, indent=2)


class ObjectInfoTool(BaseTool):
    """Get information about a specific object."""
    
    @tool_wrapper
    def execute(self, object_name: str) -> str:
        """Get detailed information about a specific object in the Blender scene."""
        # Validate object name
        validated_name = validate_object_name(object_name)
        
        result = self.send_command("get_object_info", {"name": validated_name})
        return json.dumps(result, indent=2)


class ViewportScreenshotTool(BaseTool):
    """Capture viewport screenshots."""
    
    @tool_wrapper
    def execute(self, max_size: int = 800) -> Image:
        """Capture a screenshot of the current Blender 3D viewport."""
        # Validate max_size
        if not isinstance(max_size, int) or max_size < 100 or max_size > 4096:
            raise ValidationError("max_size must be an integer between 100 and 4096")
        
        # Create secure temporary file
        temp_dir = config.get_temp_dir()
        temp_dir.mkdir(parents=True, exist_ok=True)
        
        temp_path = temp_dir / f"blender_screenshot_{os.getpid()}.png"
        
        try:
            result = self.send_command("get_viewport_screenshot", {
                "max_size": max_size,
                "filepath": str(temp_path),
                "format": "png"
            })
            
            if "error" in result:
                raise Exception(result["error"])
            
            if not temp_path.exists():
                raise Exception("Screenshot file was not created")
            
            # Check file size
            file_size_mb = temp_path.stat().st_size / (1024 * 1024)
            if file_size_mb > config.max_file_size_mb:
                raise Exception(f"Screenshot file too large: {file_size_mb:.1f}MB > {config.max_file_size_mb}MB")
            
            # Read the file
            with open(temp_path, 'rb') as f:
                image_bytes = f.read()
            
            return Image(data=image_bytes, format="png")
            
        finally:
            # Clean up temp file
            if temp_path.exists():
                try:
                    temp_path.unlink()
                except Exception as e:
                    self.logger.warning(f"Failed to clean up temp file {temp_path}: {e}")


class CodeExecutionTool(BaseTool):
    """Execute Python code in Blender."""
    
    @tool_wrapper
    def execute(self, code: str) -> str:
        """Execute arbitrary Python code in Blender."""
        # Security check
        if not config.enable_code_execution:
            raise SecurityError("Code execution is disabled")
        
        # Validate code safety
        validate_code_safety(code)
        
        # Additional length check
        if len(code.strip()) == 0:
            raise ValidationError("Code cannot be empty")
        
        self.logger.warning(f"Executing code in Blender: {code[:100]}...")
        
        result = self.send_command("execute_code", {"code": code})
        
        # Check for execution result
        if isinstance(result, dict):
            if "error" in result:
                return f"Code execution failed: {result['error']}"
            return f"Code executed successfully: {result.get('result', 'No output')}"
        
        return f"Code executed successfully: {result}"


# Tool instances
scene_info_tool = SceneInfoTool()
object_info_tool = ObjectInfoTool()
viewport_screenshot_tool = ViewportScreenshotTool()
code_execution_tool = CodeExecutionTool()


# MCP tool function wrappers
def get_scene_info(ctx: Context) -> str:
    """Get detailed information about the current Blender scene."""
    return scene_info_tool.execute()


def get_object_info(ctx: Context, object_name: str) -> str:
    """Get detailed information about a specific object in the Blender scene."""
    return object_info_tool.execute(object_name=object_name)


def get_viewport_screenshot(ctx: Context, max_size: int = 800) -> Image:
    """Capture a screenshot of the current Blender 3D viewport."""
    return viewport_screenshot_tool.execute(max_size=max_size)


def execute_blender_code(ctx: Context, code: str) -> str:
    """Execute arbitrary Python code in Blender."""
    return code_execution_tool.execute(code=code)
