from pathlib import Path
from conan import ConanFile
from conan.tools.files import get, copy


class Ros2JazzyConan(ConanFile):
    name = "ros2-jazzy-toolchain"
    # Optional but recommended for clarity in Conan 2
    package_type = "application"

    # Optional metadata
    license = "Apache-2.0"
    author = "<Put your name here> <And your email here>"
    url = "<Package recipe repository url here, for issues about the package>"
    description = "Prebuilt ROS 2 Jazzy toolchain."
    topics = ("ros2", "jazzy", "toolchain")

    # Binary configuration
    settings = "os", "arch"
    options = {"variant": ["ros_core", "ros_base"]}
    default_options = {"variant": "ros_core"}

    tc_folder = "ros2_jazzy_toolchain"

    # ---- Helpers ---------------------------------------------------------

    def _effective_target_arch(self) -> str:
        """
        Prefer the cross 'settings_target.arch' when available (toolchain mode),
        otherwise fall back to the regular 'settings.arch'.
        """
        if self.settings_target is not None:
            arch = self.settings_target.get_safe("arch")
            if arch:
                return str(arch)
        return str(self.settings.arch)

    def _variant_key(self) -> str:
        return str(self.options.variant)

    # ---- Life cycle ------------------------------------------------------

    def build(self):
        # Resolve which arch key to use in conandata
        arch_key = self._effective_target_arch()
        if "armv8" in arch_key:
            arch_key = "aarch64"
        variant_key = self._variant_key()

        # conandata.yml must be structured accordingly:
        # sources:
        #   <version>:
        #     <variant>:
        #       <arch>:
        #         url: ...
        #         sha256: ...
        src_info = self.conan_data["sources"][str(self.version)][variant_key][arch_key]
        get(self, **src_info, destination=self.tc_folder)

    def package_id(self):
        """
        When this recipe is used as a toolchain (tool_requires + --build-require),
        settings_target describes the *target* platform and should influence the
        package_id. In other contexts settings_target can be None, so we guard it.
        """
        if self.settings_target is not None:
            # Copy the target settings into the package_id model
            self.info.settings_target = self.settings_target

            # Only keep the target 'arch' dimension to distinguish e.g. armv8 vs x86_64
            self.info.settings_target.rm_safe("os")
            self.info.settings_target.rm_safe("compiler")
            self.info.settings_target.rm_safe("build_type")
        # If settings_target is None, we just keep the default package_id.

    def package(self):
        # Package everything downloaded into the package folder
        copy(self, "*", src=self.build_folder, dst=self.package_folder)

    def package_info(self):
        ros_root = Path(self.package_folder) / self.tc_folder
        # CRITICAL FIX: Convert Path to string immediately
        ros_root_str = str(ros_root)

        # Helper to prevent repetition and ensure types are correct
        def _add_env(name, value, method="define"):
            # Ensure value is always a string to prevent TypeError
            str_value = str(value)
            (
                self.buildenv_info.define(name, str_value)
                if method == "define"
                else self.buildenv_info.prepend_path(name, str_value)
            )
            (
                self.runenv_info.define(name, str_value)
                if method == "define"
                else self.runenv_info.prepend_path(name, str_value)
            )

        # 1. Standard ROS 2 Env Vars
        _add_env("AMENT_PREFIX_PATH", ros_root_str, method="prepend")
        _add_env("CMAKE_PREFIX_PATH", ros_root_str, method="prepend")
        _add_env("COLCON_PREFIX_PATH", ros_root_str, method="prepend")
        _add_env("PATH", str(ros_root / "bin"), method="prepend")

        # 2. Custom CONAN_ROS2_* Variables
        _add_env("CONAN_ROS2_ROOT", ros_root_str)  # Fixed: Now uses string

        # 3. Setup Scripts (Loop logic to reduce code size)
        scripts = ["setup", "local_setup"]
        shells = ["bash", "sh", "zsh", "ps1"]

        for script in scripts:
            for shell in shells:
                script_path = ros_root / f"{script}.{shell}"
                if script_path.exists():
                    # Define variable: e.g., CONAN_ROS2_SETUP_BASH
                    var_name = f"CONAN_ROS2_{script.upper()}_{shell.upper()}"
                    _add_env(var_name, script_path)

                    # Add convenience source command for Bash
                    if shell == "bash":
                        cmd_var = (
                            "CONAN_ROS2_SOURCE_CMD"
                            if script == "setup"
                            else "CONAN_ROS2_LOCAL_SOURCE_CMD"
                        )
                        _add_env(cmd_var, f"source {script_path}")

    def deploy(self) -> None:
        src_path = Path(self.package_folder)
        dst_path = Path(self.deploy_folder)
        copy(conanfile=self, pattern="*", src=str(src_path), dst=str(dst_path))
        self.output.success(f"Deployed files from {src_path} to {dst_path}")
