# CocoaPods helpers of @superrouteca/smap-react-native.
#
# The sMap iOS SDK is a Swift package (product `SMap`) whose rendering engine and glTF reader are dynamic binary
# frameworks of that package. The pod gets the package through React Native's spm_dependency, which links it, but Xcode embeds a
# package's binary frameworks only in an app target that depends on the package itself. Linking the package into the
# app as well would link the SDK twice, so the app target is given a build phase that embeds those frameworks,
# by `SMapReactNative.post_install(installer)` in the app's Podfile:
#
#   require Pod::Executable.execute_command('node', ['-p',
#     'require.resolve("@superrouteca/smap-react-native/ios/smap_react_native.rb", {paths: [process.argv[1]]})',
#     __dir__]).strip
#   ...
#   post_install do |installer|
#     react_native_post_install(installer, ...)
#     SMapReactNative.post_install(installer)
#   end
#
# Which package is used: SMAP_IOS_PACKAGE_PATH (a checkout of the Swift package) when set; else, inside the sMap SDK
# repository, the package next to this one; else the tag of this release from GitHub.
require "json"

module SMapReactNative
  REMOTE = "https://github.com/Goodneo-Solutions/smap-sdk.git".freeze
  PRODUCT = "SMap".freeze
  PHASE = "[sMap] Embed map engine".freeze
  # The map engine, and the glTF reader of 3D models (1.2.0).
  FRAMEWORKS = ["MapLibre.framework", "GLTFKit2.framework"].freeze

  # Copies the frameworks from the build products (where Xcode puts the package's binary frameworks; a package's
  # frameworks may also sit under PackageFrameworks) into the app's Frameworks folder and signs them as the app is
  # signed.
  EMBED_SCRIPT = <<~SH.freeze
    set -e
    dst="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
    mkdir -p "$dst"
    for fw in #{FRAMEWORKS.join(" ")}; do
      src="${BUILT_PRODUCTS_DIR}/$fw"
      [ -d "$src" ] || src="${BUILT_PRODUCTS_DIR}/PackageFrameworks/$fw"
      if [ ! -d "$src" ]; then
        echo "error: $fw not found in ${BUILT_PRODUCTS_DIR}; run pod install again"
        exit 1
      fi
      rm -rf "$dst/$fw"
      cp -R "$src" "$dst/"
      if [ "${CODE_SIGNING_ALLOWED}" = "YES" ] && [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" ]; then
        codesign --force --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements "$dst/$fw"
      fi
    done
  SH

  def self.package_root
    File.realpath(File.join(__dir__, ".."))
  end

  def self.version
    JSON.parse(File.read(File.join(package_root, "package.json")))["version"]
  end

  # The local Swift package directory, or nil for the published one.
  def self.local_sdk
    env = ENV["SMAP_IOS_PACKAGE_PATH"]
    return File.expand_path(env) if env && !env.empty?
    [File.join(package_root, "..", "ios"), File.join(package_root, "..")].map { |d| File.expand_path(d) }.find do |dir|
      manifest = File.join(dir, "Package.swift")
      File.exist?(manifest) && File.read(manifest).include?(".library(name: \"#{PRODUCT}\"")
    end
  end

  # Called by the podspec.
  def self.add_to_pod(spec)
    local = local_sdk
    if local
      spm_dependency(spec, url: local, requirement: {}, products: [PRODUCT])
    else
      spm_dependency(spec, url: REMOTE, requirement: { kind: "exactVersion", version: version }, products: [PRODUCT])
    end
  end

  # Adds the embed phase to every app target of the Podfile (once; kept up to date).
  def self.post_install(installer)
    inputs = FRAMEWORKS.map { |fw| "${BUILT_PRODUCTS_DIR}/#{fw}" }
    outputs = FRAMEWORKS.map { |fw| "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/#{fw}" }
    installer.aggregate_targets.each do |aggregate|
      project = aggregate.user_project
      next unless project
      changed = false
      aggregate.user_targets.each do |target|
        next unless target.respond_to?(:product_type) && target.product_type == "com.apple.product-type.application"
        phase = target.shell_script_build_phases.find { |p| p.name == PHASE } || target.new_shell_script_build_phase(PHASE)
        next if phase.shell_script == EMBED_SCRIPT && phase.input_paths == inputs && phase.output_paths == outputs
        phase.shell_path = "/bin/sh"
        phase.shell_script = EMBED_SCRIPT
        phase.input_paths = inputs
        phase.output_paths = outputs
        Pod::UI.puts "[sMap] #{target.name} embeds the map engine frameworks"
        changed = true
      end
      project.save if changed
    end
  end
end
