import os

import lldb

from jb_lldb_commands_utils import str_to_bool
from renderers.jb_lldb_logging_manager import RENDER_LOG


def _is_cpp_builtin_primitive_type_name(name: str) -> bool:
    return "std::" not in name and "cxx::" not in name


def _prioritize_cpp_builtin_formatters(debugger: lldb.SBDebugger):
    cpp_category: lldb.SBTypeCategory = debugger.GetCategory(lldb.eLanguageTypeC_plus_plus)
    RENDER_LOG.info("Enabling '%s' category for built-in formatters", cpp_category.GetName())
    cpp_category.SetEnabled(True)

    # Remove summaries and synthetics for primitive types, because 'jb_formatters' provides them
    cpp_summary_name_specifiers: list[lldb.SBTypeNameSpecifier] = [
        cpp_category.GetTypeNameSpecifierForSummaryAtIndex(i) for i in range(cpp_category.GetNumSummaries())
    ]

    for cpp_summary_name_specifier in cpp_summary_name_specifiers:
        name: str = cpp_summary_name_specifier.GetName()
        if _is_cpp_builtin_primitive_type_name(name):
            RENDER_LOG.debug("Removing summary for type '%s'", name)
            cpp_category.DeleteTypeSummary(cpp_summary_name_specifier)

    cpp_synthetic_name_specifiers: list[lldb.SBTypeNameSpecifier] = [
        cpp_category.GetTypeNameSpecifierForSyntheticAtIndex(i) for i in range(cpp_category.GetNumSynthetics())
    ]

    for cpp_synthetic_name_specifier in cpp_synthetic_name_specifiers:
        name: str = cpp_synthetic_name_specifier.GetName()
        if _is_cpp_builtin_primitive_type_name(name):
            RENDER_LOG.debug("Removing synthetic for type '%s'", name)
            cpp_category.DeleteTypeSynthetic(cpp_synthetic_name_specifier)


def initialize_jb_formatters_category(debugger: lldb.SBDebugger) -> str:
    category_name = "jb_formatters"

    RENDER_LOG.info("Initializing '%s' category", category_name)

    default_categories = {"default", "VectorTypes", "system"}
    user_defined_categories = []
    for i in range(debugger.GetNumCategories()):
        category: lldb.SBTypeCategory = debugger.GetCategoryAtIndex(i)
        if category.GetEnabled() and category.GetName() not in default_categories:
            user_defined_categories.append(category)

    debugger.CreateCategory(category_name).SetEnabled(True)

    if str_to_bool(os.environ.get("LLDB_NATVIS_PRIORITIZE_CPP_BUILTIN_FORMATTERS", "0")):
        _prioritize_cpp_builtin_formatters(debugger)

    # Re-enable all user-defined categories to prioritize them over 'jb_formatters'
    for user_category in user_defined_categories:
        RENDER_LOG.info("Re-enabling category '%s'", user_category.GetName())
        user_category.SetEnabled(True)

    return category_name
