import json
import logging
from typing import Any, Dict, List, cast
from linode_api4 import LinodeClient
from linode_api4.objects import Region

logger = logging.getLogger(__name__)

def register_tools(mcp_server: Any, linode_client: LinodeClient):
    """
    Register all Linode tools with the MCP server
    
    Args:
        mcp_server: The MCP server instance
        linode_client: The initialized Linode client
    """
    # Store the Linode client reference for tool access
    mcp_server.linode_client = linode_client
    
    # List regions
    @mcp_server.tool(name="list_regions")
    def list_regions(random_string: str = "") -> str:
        """List all available Linode regions"""
        try:
            # Get the regions list
            regions_list = linode_client.regions()
            
            # Process each region in the collection
            result = []
            # Type annotation to help linter
            for item in regions_list:
                # Cast to Region type to resolve linting issues
                region = cast(Region, item)
                result.append({
                    "id": region.id,
                    "country": region.country,
                    "status": region.status,
                    "capabilities": region.capabilities
                })
                
            return json.dumps(result)
        except Exception as e:
            logger.error(f"Error listing regions: {str(e)}")
            return json.dumps({"error": str(e)})

    # List instance types with pricing
    @mcp_server.tool(name="list_instance_types")
    def list_instance_types(random_string: str = "") -> str:
        """List all available Linode instance types and their pricing"""
        try:
            types = linode_client.linode.types.all()
            result = [{
                "id": type.id,
                "label": type.label,
                "vcpus": type.vcpus,
                "memory": type.memory,
                "disk": type.disk,
                "transfer": type.transfer,
                "price_monthly": type.price.monthly,
                "price_hourly": type.price.hourly
            } for type in types]
            return json.dumps(result)
        except Exception as e:
            logger.error(f"Error listing instance types: {str(e)}")
            return json.dumps({"error": str(e)})

    # List instances
    @mcp_server.tool(name="list_instances")
    def list_instances(random_string: str = "") -> str:
        """List all existing Linode instances"""
        try:
            instances = linode_client.linode.instances.all()
            result = [{
                "id": instance.id,
                "label": instance.label,
                "region": instance.region.id,
                "type": instance.type.id,
                "status": instance.status,
                "ipv4": instance.ipv4,
                "created": str(instance.created),
                "updated": str(instance.updated)
            } for instance in instances]
            return json.dumps(result)
        except Exception as e:
            logger.error(f"Error listing instances: {str(e)}")
            return json.dumps({"error": str(e)})

    # Create instance
    @mcp_server.tool(name="create_instance")
    def create_instance(label: str, region: str, type: str, image: str, root_pass: str) -> str:
        """
        Create a new Linode instance
        
        Args:
            label: Label for the Linode
            region: Region ID (use list_regions to see available options)
            type: Instance type ID (use list_instance_types to see available options)
            image: Image ID (e.g., 'linode/debian11')
            root_pass: Strong password for the root user
        """
        try:
            # Input validation
            if len(root_pass) < 8:
                return json.dumps({"error": "Root password must be at least 8 characters"})
                
            # Create the instance
            instance = linode_client.linode.instances.create(
                type=type,
                region=region,
                image=image,
                label=label,
                root_pass=root_pass
            )
            
            result = {
                "id": instance.id,
                "label": instance.label,
                "status": instance.status,
                "ipv4": instance.ipv4,
                "region": instance.region.id,
                "type": instance.type.id
            }
            return json.dumps(result)
        except Exception as e:
            logger.error(f"Error creating instance: {str(e)}")
            return json.dumps({"error": str(e)})
                
    # Get instance details
    @mcp_server.tool(name="get_instance")
    def get_instance(id: int) -> str:
        """
        Get details about a specific Linode instance
        
        Args:
            id: Linode instance ID
        """
        try:
            instance = linode_client.linode.instances.get(id)
            
            result = {
                "id": instance.id,
                "label": instance.label,
                "status": instance.status,
                "ipv4": instance.ipv4,
                "ipv6": instance.ipv6,
                "region": instance.region.id,
                "type": instance.type.id,
                "specs": {
                    "disk": instance.specs.disk,
                    "memory": instance.specs.memory,
                    "vcpus": instance.specs.vcpus,
                    "transfer": instance.specs.transfer
                },
                "created": str(instance.created),
                "updated": str(instance.updated)
            }
            return json.dumps(result)
        except Exception as e:
            logger.error(f"Error getting instance details: {str(e)}")
            return json.dumps({"error": str(e)})
                
    # Delete instance
    @mcp_server.tool(name="delete_instance")
    def delete_instance(id: int) -> str:
        """
        Delete a Linode instance
        
        Args:
            id: Linode instance ID
        """
        try:
            instance = linode_client.linode.instances.get(id)
            instance_label = instance.label
            instance.delete()
            
            return json.dumps({
                "success": True,
                "message": f"Instance {id} ({instance_label}) has been deleted"
            })
        except Exception as e:
            logger.error(f"Error deleting instance: {str(e)}")
            return json.dumps({"error": str(e)})
                
    # Reboot instance
    @mcp_server.tool(name="reboot_instance")
    def reboot_instance(id: int) -> str:
        """
        Reboot a Linode instance
        
        Args:
            id: Linode instance ID
        """
        try:
            instance = linode_client.linode.instances.get(id)
            instance.reboot()
            
            return json.dumps({
                "success": True,
                "message": f"Instance {id} reboot initiated"
            })
        except Exception as e:
            logger.error(f"Error rebooting instance: {str(e)}")
            return json.dumps({"error": str(e)}) 