import textwrap

from conans.client.generators.cmake import DepsCppCmake
from conans.client.generators.cmake_find_package_common import (target_template,
                                                                CMakeFindPackageCommonMacros,
                                                                find_transitive_dependencies)
from conans.client.generators.cmake_multi import extend
from conans.model import Generator


class CMakeFindPackageGenerator(Generator):
    find_template = textwrap.dedent("""
        {macros_and_functions}

        include(FindPackageHandleStandardArgs)

        conan_message(STATUS "Conan: Using autogenerated Find{name}.cmake")
        # Global approach
        set({name}_FOUND 1)
        set({name}_VERSION "{version}")

        find_package_handle_standard_args({name} REQUIRED_VARS
                                          {name}_VERSION VERSION_VAR {name}_VERSION)
        mark_as_advanced({name}_FOUND {name}_VERSION)

        {find_libraries_block}
        if(NOT ${{CMAKE_VERSION}} VERSION_LESS "3.0")
            # Target approach
            if(NOT TARGET {name}::{name})
                add_library({name}::{name} INTERFACE IMPORTED)
                if({name}_INCLUDE_DIRS)
                    set_target_properties({name}::{name} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
                                          "${{{name}_INCLUDE_DIRS}}")
                endif()
                set_property(TARGET {name}::{name} PROPERTY INTERFACE_LINK_LIBRARIES
                             "${{{name}_LIBRARIES_TARGETS}};${{{name}_LINKER_FLAGS_LIST}}")
                set_property(TARGET {name}::{name} PROPERTY INTERFACE_COMPILE_DEFINITIONS
                             ${{{name}_COMPILE_DEFINITIONS}})
                set_property(TARGET {name}::{name} PROPERTY INTERFACE_COMPILE_OPTIONS
                             "${{{name}_COMPILE_OPTIONS_LIST}}")
                {find_dependencies_block}
            endif()
        endif()
        """)

    @property
    def filename(self):
        return None

    @property
    def content(self):
        ret = {}
        for _, cpp_info in self.deps_build_info.dependencies:
            depname = cpp_info.get_name("cmake_find_package")
            ret["Find%s.cmake" % depname] = self._find_for_dep(depname, cpp_info)
        return ret

    def _find_for_dep(self, name, cpp_info):
        # The common macros
        macros_and_functions = "\n".join([
            CMakeFindPackageCommonMacros.conan_message,
            CMakeFindPackageCommonMacros.apple_frameworks_macro,
            CMakeFindPackageCommonMacros.conan_package_library_targets,
            ])

        # compose the cpp_info with its "debug" or "release" specific config
        dep_cpp_info = cpp_info
        build_type = self.conanfile.settings.get_safe("build_type")
        if build_type:
            dep_cpp_info = extend(dep_cpp_info, build_type.lower())

        # The find_libraries_block, all variables for the package, and creation of targets
        public_deps_names = [self.deps_build_info[dep].get_name("cmake_find_package") for dep in
                             dep_cpp_info.public_deps]
        deps_names = ";".join(["{n}::{n}".format(n=n) for n in public_deps_names])

        deps = DepsCppCmake(dep_cpp_info)
        find_libraries_block = target_template.format(name=name, deps=deps, build_type_suffix="",
                                                      deps_names=deps_names)

        # The find_transitive_dependencies block
        find_dependencies_block = ""
        if dep_cpp_info.public_deps:
            # Here we are generating FindXXX, so find_modules=True
            f = find_transitive_dependencies(public_deps_names, find_modules=True)
            # proper indentation
            find_dependencies_block = ''.join("        " + line if line.strip() else line
                                              for line in f.splitlines(True))

        tmp = self.find_template.format(name=name, version=dep_cpp_info.version,
                                        find_libraries_block=find_libraries_block,
                                        find_dependencies_block=find_dependencies_block,
                                        macros_and_functions=macros_and_functions)
        return tmp
