"""{{ module_description }}

This module implements a MADSci REST node for the {{ module_name }} robot arm
with material handling operations (pick, place, move, home) and
resource management using templates and slots.

Generated by: madsci new module --template module/robot_arm
Template version: {{ template_version }}
"""

import argparse
import time
from typing import Any

from madsci.common.types.resource_types import Slot
from madsci.node_module.helpers import action
from madsci.node_module.rest_node_module import RestNode

from {{ module_name }}_interface import {{ module_name | pascal_case }}Interface
from {{ module_name }}_fake_interface import {{ module_name | pascal_case }}FakeInterface
from {{ module_name }}_types import {{ module_name | pascal_case }}NodeConfig


class {{ module_name | pascal_case }}Node(RestNode):
    """{{ module_description }}

    This node provides a REST API for controlling the {{ module_name }} robot arm
    with material handling operations and resource tracking.

    Node Architecture:
    - Inherits from RestNode for HTTP API exposure
    - Uses @action decorator to expose callable methods
    - Manages resources through ResourceClient integration
    - Logs all operations through EventClient

    Resource Management:
    - Creates and manages arm slot templates (Slot resources)
    - Initializes arm slot resource instances
    - Tracks resource state changes
    """

    # Hardware interface instance (initialized in startup_handler)
    _interface: Any = None

    # Configuration instance with node-specific settings
    config: {{ module_name | pascal_case }}NodeConfig = {{ module_name | pascal_case }}NodeConfig()

    # Pydantic model class for configuration validation
    config_model = {{ module_name | pascal_case }}NodeConfig

    def startup_handler(self) -> None:
        """Initialize the robot arm node and create resource templates.

        This method is called when the node starts up or restarts. It performs:
        1. Hardware interface initialization (real or fake based on config)
        2. Robot arm connection, initialization, and homing
        3. Resource template creation for arm slots
        4. Instantiation of specific resources
        5. Registration of resources with the resource manager
        """
        # Create the appropriate interface based on configuration
        if self.config.interface_type == "fake":
            self._interface = {{ module_name | pascal_case }}FakeInterface()
        else:
            self._interface = {{ module_name | pascal_case }}Interface()

        # Connect to the robot arm, initialize, and home it
        self._interface.connect()
        self._interface.initialize()
        self._interface.home()

        # Create arm slot template - represents positions where items can be placed
        arm_slot = Slot(
            resource_name="{{ module_name }}_slot",
            resource_class="{{ module_name | pascal_case }}Slot",
            capacity=1,
            attributes={
                "slot_type": "arm_gripper",
                "accessible": True,
                "description": "{{ module_name | pascal_case }} robot arm gripper slot",
            },
        )

        self.resource_client.init_template(
            resource=arm_slot,
            template_name="{{ module_name }}_slot",
            description=(
                "Template for {{ module_name }} arm slot. "
                "Represents the gripper position on the robot arm."
            ),
            required_overrides=["resource_name"],
            tags=["{{ module_name }}", "slot", "robot-arm"],
            created_by=self.node_definition.node_id,
            version="1.0.0",
        )

        # Initialize arm slot resource instance
        slot_resource_name = f"{{ module_name }}_slot_{self.node_definition.node_name}"
        self.arm_slot = self.resource_client.create_resource_from_template(
            template_name="{{ module_name }}_slot",
            resource_name=slot_resource_name,
            add_to_database=True,
        )
        self.logger.log(
            f"Initialized arm slot resource from template: {self.arm_slot.resource_id}"
        )

        self.logger.log("{{ module_name | pascal_case }} robot arm node initialized!")

    def shutdown_handler(self) -> None:
        """Clean shutdown of the robot arm node.

        This method is called when the node is being shut down or restarted.
        It safely shuts down the arm and closes connections.
        """
        self.logger.log("Shutting down {{ module_name }} robot arm node")
        if self._interface:
            self._interface.shutdown()
            self._interface.disconnect()

    def state_handler(self) -> dict[str, Any]:
        """Report current node state for monitoring and debugging.

        This method is called periodically by the MADSci framework to collect
        node status information for dashboard displays, health monitoring,
        and scheduling decisions.

        Returns:
            dict: Current node state including robot arm status information.
        """
        if self._interface and self._interface.is_connected:
            self.node_state = self._interface.get_status()

    @action
    def home(self) -> str:
        """Home the robot arm.

        This action moves the robot arm to its calibrated home/reference
        position. Should be called before performing pick/place operations
        or after an error recovery.

        Returns:
            str: Confirmation message.
        """
        self._interface.home()
        time.sleep(self.config.wait_time)
        return "Robot arm homed successfully"

    @action
    def pick(self, location: str = "") -> dict:
        """Pick up an item from a named location.

        This action commands the robot arm to pick up an item from the
        specified location using the gripper.

        Args:
            location: Name of the location to pick from.

        Returns:
            dict: Result of the pick operation.
        """
        result = self._interface.pick(location)
        time.sleep(self.config.wait_time)
        return result

    @action
    def place(self, location: str = "") -> dict:
        """Place an item at a named location.

        This action commands the robot arm to place a held item at the
        specified location.

        Args:
            location: Name of the location to place at.

        Returns:
            dict: Result of the place operation.
        """
        result = self._interface.place(location)
        time.sleep(self.config.wait_time)
        return result

    @action
    def move_to(self, x: float = 0.0, y: float = 0.0, z: float = 0.0) -> dict:
        """Move the robot arm to a specific position.

        This action commands the robot arm to move to the specified
        XYZ coordinates.

        Args:
            x: Target X coordinate in mm.
            y: Target Y coordinate in mm.
            z: Target Z coordinate in mm.

        Returns:
            dict: Result of the move operation including final position.
        """
        result = self._interface.move(x, y, z, speed=self.config.default_speed)
        time.sleep(self.config.wait_time)
        return result

    @action
    def get_arm_status(self) -> dict:
        """Get the current status of the robot arm.

        This action queries the robot arm for its current status information,
        including connection state, initialization state, homing state,
        holding state, and position data.

        Returns:
            dict: Robot arm status information.
        """
        return self._interface.get_status()


def main() -> None:
    """Entry point for the {{ module_name }} robot arm node."""
    parser = argparse.ArgumentParser(description="{{ module_description }}")
    parser.add_argument(
        "--fake",
        action="store_true",
        help="Use fake interface for testing without hardware",
    )
    parser.add_argument(
        "--port",
        type=int,
        default={{ port }},
        help="Port to run the node on (default: {{ port }})",
    )
    args = parser.parse_args()

    node = {{ module_name | pascal_case }}Node()
    if args.fake:
        node.config.interface_type = "fake"
    node.config.node_url = f"http://localhost:{args.port}/"
    node.start_node()


if __name__ == "__main__":
    main()
