from __future__ import annotations

from pathlib import Path


class PathUtils:
    @staticmethod
    def to_module_path(
        path_str: str, 
        root_path: Path | None = None, 
        prefix_mapping: dict[str, str] | None = None
    ) -> str:
        """
        Converts a file path to a Python module path (dot notation).
        Example: 'solutions/_gen/assets/fields/common/table.py' -> 'solutions._gen.assets.fields.common.table'
        
        Args:
            path_str: Path string to convert.
            root_path: Optional project root to anchor relative resolution.
            prefix_mapping: Optional dict of {sub_path: alias} to override namespaces.
        """
        try:
            p = Path(path_str)
            if root_path and p.is_absolute():
                try:
                    # Attempt to make path relative to root_path
                    p = p.relative_to(root_path)
                except ValueError:
                    # Logic for fallback roots
                    fallback_roots = [
                        Path("_gen/metadata"),
                        Path("test_prj/dataobjects/globals"),
                        Path("_gen/assets/globals"),
                        Path("dataobjects/globals"),
                    ]
                    for fb_root in fallback_roots:
                        try:
                            p = p.relative_to(fb_root)
                            break
                        except ValueError:
                            continue
            
            # Remove .py suffix
            if p.suffix == ".py":
                p = p.with_suffix("")
            
            p_str = str(p)
            
            # Apply prefix mapping if provided
            if prefix_mapping:
                # Sort mappings length descending to ensure most specific match
                sorted_mappings = sorted(prefix_mapping.items(), key=lambda x: len(x[0]), reverse=True)
                for sub_path, alias in sorted_mappings:
                    # Match sub_path exactly or as a directory parent
                    if p_str == sub_path or p_str.startswith(f"{sub_path}/"):
                        rel = p_str[len(sub_path):].strip("/")
                        if rel:
                             res = f"{alias}.{rel.replace('/', '.')}"
                             return res.lstrip(".")  # Final safety strip
                        return alias.lstrip(".")

            # Convert format: slash to dot, and strip leading dots to prevent relative imports
            result = p_str.replace("/", ".").lstrip(".")
            return result
        except Exception:
            return path_str

    @staticmethod
    def build_prefix_mapping(params: dict, project_root: Path) -> dict[str, str]:
        """
        Builds a prefix mapping based on configuration parameters.
        Commonly handles fields_package_prefix.
        """
        mapping = {}
        
        # 1. Datacube Fields Prefix
        pkg_prefix = params.get("generation", {}).get("fields_package_prefix")
        if pkg_prefix:
            # Determine physical root
            # Priority: field_maps_dir (target) > folder_prefix (legacy)
            fm_dir = params.get("paths", {}).get("target", {}).get("field_maps_dir")
            if not fm_dir:
                folder_prefix = params.get("paths", {}).get("target", {}).get("datacubes_dir") or params.get("folder_prefix") or "_gen/assets/"
                fields_suffix = params.get("generation", {}).get("fields_subpackage") or params.get("fields_module_root") or "fields"
                fm_dir = str(Path(folder_prefix) / fields_suffix)

            fm_path = Path(fm_dir)
            try:
                if fm_path.is_absolute():
                    rel_fm = str(fm_path.relative_to(project_root))
                else:
                    rel_fm = str(fm_path)
                
                mapping[rel_fm] = pkg_prefix
                # Also map without leading dot for robustness
                if rel_fm.startswith("."):
                    mapping[rel_fm.lstrip(".")] = pkg_prefix
            except Exception:
                mapping[str(fm_path)] = pkg_prefix

        return mapping
