import os
import pathlib

import conan
import conan.tools.build
import conan.tools.cmake
import conan.tools.files

import modulus.config

config = modulus.config

class modulus_recipe(conan.ConanFile):
  name = "modulus"
  version = "latest"
  description = "Shared Conan/CMake tooling and C++23 utility framework"
  license = "Proprietary"
  package_type = "library"
  settings = "os", "arch", "compiler", "build_type"
  options = {
    "shared": [
      True,
      False,
    ],
    "fPIC": [
      True,
      False,
    ],
    "with_tests": [
      True,
      False,
    ],
    "with_openssl": [
      True,
      False,
    ],
    "with_sqlite": [
      True,
      False,
    ],
    "with_gpiod": [
      True,
      False,
    ],
    "with_opencv": [
      True,
      False,
    ],
    "with_raylib": [
      True,
      False,
    ],
    "with_tensorflowlite": [
      True,
      False,
    ],
  }
  default_options = {
    "shared": False,
    "fPIC": True,
    "with_tests": False,
    "with_openssl": False,
    "with_sqlite": False,
    "with_gpiod": False,
    "with_opencv": False,
    "with_raylib": False,
    "with_tensorflowlite": False,
    "opencv/*:alphamat": False,
    "opencv/*:aruco": False,
    "opencv/*:bgsegm": False,
    "opencv/*:bioinspired": False,
    "opencv/*:calib3d": False,
    "opencv/*:ccalib": False,
    "opencv/*:cudaarithm": False,
    "opencv/*:cudabgsegm": False,
    "opencv/*:cudacodec": False,
    "opencv/*:cudafeatures2d": False,
    "opencv/*:cudafilters": False,
    "opencv/*:cudaimgproc": False,
    "opencv/*:cudalegacy": False,
    "opencv/*:cudaobjdetect": False,
    "opencv/*:cudaoptflow": False,
    "opencv/*:cudastereo": False,
    "opencv/*:cudawarping": False,
    "opencv/*:cvv": False,
    "opencv/*:datasets": False,
    "opencv/*:dnn": False,
    "opencv/*:dnn_objdetect": False,
    "opencv/*:dnn_superres": False,
    "opencv/*:dpm": False,
    "opencv/*:face": False,
    "opencv/*:features2d": False,
    "opencv/*:flann": False,
    "opencv/*:freetype": False,
    "opencv/*:fuzzy": False,
    "opencv/*:gapi": False,
    "opencv/*:hdf": False,
    "opencv/*:hfs": False,
    "opencv/*:highgui": False,
    "opencv/*:img_hash": False,
    "opencv/*:imgcodecs": True,
    "opencv/*:imgproc": True,
    "opencv/*:intensity_transform": False,
    "opencv/*:line_descriptor": False,
    "opencv/*:mcc": False,
    "opencv/*:ml": False,
    "opencv/*:nonfree": False,
    "opencv/*:objdetect": False,
    "opencv/*:optflow": False,
    "opencv/*:ovis": False,
    "opencv/*:parallel": False,
    "opencv/*:phase_unwrapping": False,
    "opencv/*:photo": False,
    "opencv/*:plot": False,
    "opencv/*:quality": False,
    "opencv/*:rapid": False,
    "opencv/*:reg": False,
    "opencv/*:rgbd": False,
    "opencv/*:saliency": False,
    "opencv/*:sfm": False,
    "opencv/*:shape": False,
    "opencv/*:stereo": False,
    "opencv/*:stitching": False,
    "opencv/*:structured_light": False,
    "opencv/*:superres": False,
    "opencv/*:surface_matching": False,
    "opencv/*:text": False,
    "opencv/*:tracking": False,
    "opencv/*:video": False,
    "opencv/*:videoio": False,
    "opencv/*:videostab": False,
    "opencv/*:viz": False,
    "opencv/*:wechat_qrcode": False,
    "opencv/*:with_avif": False,
    "opencv/*:with_cuda": False,
    "opencv/*:with_eigen": False,
    "opencv/*:with_ffmpeg": False,
    "opencv/*:with_flatbuffers": False,
    "opencv/*:with_gdal": False,
    "opencv/*:with_gdcm": False,
    "opencv/*:with_gtk": False,
    "opencv/*:with_imgcodec_hdr": False,
    "opencv/*:with_imgcodec_pfm": False,
    "opencv/*:with_imgcodec_pxm": False,
    "opencv/*:with_imgcodec_sunraster": False,
    "opencv/*:with_ipp": False,
    "opencv/*:with_jpeg": "libjpeg",
    "opencv/*:with_jpeg2000": False,
    "opencv/*:with_opencl": False,
    "opencv/*:with_openexr": False,
    "opencv/*:with_openvino": False,
    "opencv/*:with_png": True,
    "opencv/*:with_protobuf": False,
    "opencv/*:with_qt": False,
    "opencv/*:with_quirc": False,
    "opencv/*:with_tiff": False,
    "opencv/*:with_v4l": False,
    "opencv/*:with_vulkan": False,
    "opencv/*:with_wayland": False,
    "opencv/*:with_webp": False,
    "opencv/*:world": False,
    "opencv/*:xfeatures2d": False,
    "opencv/*:ximgproc": False,
    "opencv/*:xobjdetect": False,
    "opencv/*:xphoto": False,
    "raylib/*:camera_system": False,
    "raylib/*:custom_frame_control": True,
    "raylib/*:customize_build": True,
    "raylib/*:gestures_system": True,
    "raylib/*:module_raudio": False,
    "raylib/*:opengl_version": "ES-2.0",
    "raylib/*:rprand_generator": False,
    "glfw/*:with_wayland": False,
    "glfw/*:with_x11": False,
  }
  exports = "modulus/*.py", "modulus.json"
  exports_sources = (
    "CMakeLists.txt",
    "cmake/*.cmake",
    "cmake/*.in",
    "include/*.hpp",
    "include/modulus/*.hpp",
    "src/*.cpp",
    "tests/CMakeLists.txt",
    "tests/*.cpp",
    "tests/*.hpp",
    "package/CMakeLists.txt",
    "package/conanfile.py",
    "package/*.cpp",
    "schemas/*.json",
    "tools/*.py",
    "tools/conan/profiles/*",
    "tools/docker/*",
    "tools/editor/*",
    "README.md",
  )

  def config_options(self):
    settings = self.settings
    options = self.options
    if settings.os == "Windows":
      del options.fPIC

  def configure(self):
    options = self.options
    if options.shared:
      del options.fPIC

  def requirements(self):
    config = modulus.config.load_recipe_config(self)
    self.requires(
      modulus.config.boost_ref(config),
      transitive_headers=True,
      transitive_libs=True,
      options=modulus.config.boost_requirement_options(config),
    )
    if self.options.with_openssl:
      self.requires(
        "openssl/4.0.1",
        transitive_headers=True,
        transitive_libs=True,
      )
    if self.options.with_sqlite:
      self.requires(
        "sqlite3/3.53.2",
        transitive_headers=True,
        transitive_libs=True,
      )
    if self.options.with_gpiod:
      self.requires(
        "libgpiod/2.1",
        transitive_headers=True,
        transitive_libs=True,
      )
    if self.options.with_opencv:
      self.requires(
        "opencv/4.13.0",
        transitive_headers=True,
        transitive_libs=True,
      )
    if self.options.with_raylib:
      self.requires(
        "raylib/6.0",
        transitive_headers=True,
        transitive_libs=True,
      )
    if self.options.with_tensorflowlite:
      self.requires(
        "tensorflow-lite/2.15.0",
        transitive_headers=True,
        transitive_libs=True,
      )

  def generate(self):
    options = self.options
    deps = conan.tools.cmake.CMakeDeps(self)
    deps.generate()
    toolchain = conan.tools.cmake.CMakeToolchain(self)
    if hasattr(toolchain, "user_presets_path"):
      toolchain.user_presets_path = False
    toolchain.variables["BUILD_SHARED_LIBS"] = bool(options.shared)
    toolchain.variables["BUILD_TESTING"] = bool(options.with_tests)
    toolchain.generate()

  def build(self):
    options = self.options
    cmake = conan.tools.cmake.CMake(self)
    cmake.configure()
    cmake.build()
    if options.with_tests and conan.tools.build.can_run(self):
      cmake.test(target="check")

  def package_id(self):
    self.info.options.rm_safe("with_tests")

  def package(self):
    cmake = conan.tools.cmake.CMake(self)
    cmake.install()
    package = pathlib.Path(self.package_folder)
    conan.tools.files.copy(self, "*.py", src=pathlib.Path(self.recipe_folder) / "modulus", dst=package / "modulus", keep_path=True)
    conan.tools.files.copy(self, "*", src=pathlib.Path(self.source_folder) / "tools", dst=package / "tools", keep_path=True)

  def package_info(self):
    cpp_info = self.cpp_info
    cpp_info.set_property("cmake_file_name", "modulus")
    cpp_info.set_property("cmake_target_name", "modulus::all")
    cpp_info.set_property(
      "cmake_build_modules",
      [os.path.join("lib", "cmake", "modulus", "modulus_third_party.cmake")],
    )
    components = cpp_info.components
    components["modulus"].set_property("cmake_target_name", "modulus::modulus")
    components["modulus"].libs = ["modulus"]
    components["modulus"].requires = ["boost::json"]

    components["boost_json"].set_property("cmake_target_name", "modulus::boost_json")
    components["boost_json"].requires = ["boost::json"]

    if self.options.with_openssl:
      components["openssl"].set_property("cmake_target_name", "modulus::openssl")
      components["openssl"].requires = ["openssl::ssl", "openssl::crypto"]

    if self.options.with_sqlite:
      components["sqlite"].set_property("cmake_target_name", "modulus::sqlite")
      components["sqlite"].requires = ["sqlite3::sqlite"]

    if self.options.with_gpiod:
      components["gpiod"].set_property("cmake_target_name", "modulus::gpiod")
      components["gpiod"].requires = ["libgpiod::gpiod"]

    if self.options.with_opencv:
      components["opencv"].set_property("cmake_target_name", "modulus::opencv")
      components["opencv"].requires = [
        "opencv::opencv_core",
        "opencv::opencv_imgproc",
        "opencv::opencv_imgcodecs",
      ]

    if self.options.with_raylib:
      components["raylib"].set_property("cmake_target_name", "modulus::raylib")
      components["raylib"].requires = ["raylib::raylib"]
      if self.settings.os == "Linux":
        components["raylib"].system_libs = [
          "EGL",
          "GLESv2",
          "drm",
          "gbm",
          "atomic",
          "dl",
        ]

    if self.options.with_tensorflowlite:
      components["tensorflowlite"].set_property("cmake_target_name", "modulus::tensorflowlite")
      components["tensorflowlite"].requires = ["tensorflow-lite::tensorflow-lite"]
