# CRITICAL: Enable React Native New Architecture (required for RunAnywhere SDK)
ENV['RCT_NEW_ARCH_ENABLED'] = '1'

# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
  'require.resolve(
    "react-native/scripts/react_native_pods.rb",
    {paths: [process.argv[1]]},
  )', __dir__]).strip

# RunAnywhere SDK follows the Swift source-of-truth minimum.
platform :ios, '17.5'
prepare_react_native_project!

# react-native-permissions setup
def node_require(script)
  # Resolve script with node to allow for hoisting
  require Pod::Executable.execute_command('node', ['-p',
    "require.resolve(
      '#{script}',
      {paths: [process.argv[1]]},
    )", __dir__]).strip
end

node_require('react-native-permissions/scripts/setup.rb')

# Only include the permissions we need
setup_permissions([
  'Microphone',
  'Camera',
  'PhotoLibrary',
])

linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
  use_frameworks! :linkage => linkage.to_sym
end

target 'RunAnywhereAI' do
  config = use_native_modules!

  # Ensure NitroModules podspec is resolved locally (required by RunAnywhereLlama)
  pod 'NitroModules', :path => '../node_modules/react-native-nitro-modules'

  use_react_native!(
    :path => config[:reactNativePath],
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/..",
    # Enable New Architecture (TurboModules + Fabric)
    :hermes_enabled => true,
    :fabric_enabled => true
  )

  target 'RunAnywhereAITests' do
    inherit! :complete
    # Pods for testing
  end

  post_install do |installer|
    # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
    react_native_post_install(
      installer,
      config[:reactNativePath],
      :mac_catalyst_enabled => false
      # :ccache_enabled => true
    )

    # Force all pods to use the Swift source-of-truth deployment target.
    installer.pods_project.targets.each do |target|
      target.build_configurations.each do |config|
        config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '17.5'
        config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'x86_64'
      end
    end

    # Local core xcframeworks are built for device arm64 + simulator arm64.
    # Keep the app project aligned so Xcode does not try to compile/link x86_64.
    installer.aggregate_targets.map(&:user_project).uniq.each do |project|
      project.targets.each do |target|
        target.build_configurations.each do |config|
          config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'x86_64'
        end
      end
      project.build_configurations.each do |config|
        config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'x86_64'
      end
      project.save
    end

    # Fix Xcode 16 sandbox issue for script phases.
    #
    # IMPORTANT: do NOT mark "[CP] Copy XCFrameworks" phases as always-out-of-date.
    # On Xcode 26, always_out_of_date = "1" makes the build system IGNORE a phase's
    # output file list for dependency analysis. The Copy XCFrameworks phase is what
    # stages the vendored static libraries (librac_commons.a, librac_backend_*.a)
    # into ${PODS_XCFRAMEWORKS_BUILD_DIR}; the app link step consumes them via
    # `-force_load`/`-l`. If that phase's outputs are untracked, the linker has no
    # declared producer for those .a files and the build fails with:
    #   "Build input file cannot be found:
    #    .../XCFrameworkIntermediates/RunAnywhereCore/librac_commons.a.
    #    Did you forget to declare this file as an output of a script phase ...?"
    # Keep dependency analysis on those copy phases so the link is correctly ordered.
    installer.pods_project.targets.each do |target|
      target.build_phases.each do |phase|
        next unless phase.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
        next if phase.respond_to?(:name) && phase.name.to_s.include?('Copy XCFrameworks')
        phase.always_out_of_date = "1"
      end
    end

    # Fix RNZipArchive compiler flags issue (Xcode 16+ compatibility)
    # The RNZipArchive podspec uses -G flag which is unsupported on arm64-apple-ios targets
    # in Xcode 16+. We must fix this at two levels:
    #   1. Build settings (OTHER_CFLAGS) - full replacement with known required flags
    #   2. Per-file compiler flags - surgical removal of -G only
    installer.pods_project.targets.each do |target|
      if target.name == 'RNZipArchive'
        target.build_configurations.each do |config|
          # Full replacement of OTHER_CFLAGS for RNZipArchive.
          # We intentionally discard any existing flags because:
          #   - RNZipArchive's podspec sets problematic flags including -G
          #   - The required flags are well-known (minizip compile definitions)
          #   - $(inherited) ensures project-level flags are still included
          config.build_settings['OTHER_CFLAGS'] = '$(inherited) -DHAVE_INTTYPES_H -DHAVE_PKCRYPT -DHAVE_STDINT_H -DHAVE_WZAES -DHAVE_ZLIB -DMZ_ZIP_NO_SIGNING'
        end

        # Completely clear per-file COMPILER_FLAGS.
        # The RNZipArchive podspec sets malformed flags like:
        #   -G CC_PREPROCESSOR_DEFINITIONS="..."
        # Both -G and CC_PREPROCESSOR_DEFINITIONS= syntax are invalid.
        # Since we set proper flags via OTHER_CFLAGS above, we can safely clear these.
        target.build_phases.each do |phase|
          next unless phase.respond_to?(:files)
          phase.files.each do |file|
            next unless file.settings && file.settings['COMPILER_FLAGS']
            file.settings.delete('COMPILER_FLAGS')
          end
        end
      end
    end

    # Xcode 26.4 + RN 0.83.1: fmt's consteval path trips AppleClang during pod
    # compilation. fmt 11's header overwrites FMT_USE_CONSTEVAL after reading
    # compiler feature macros, so use C++17 for this pod to keep that path off.
    installer.pods_project.targets.each do |target|
      next unless target.name == 'fmt'

      target.build_configurations.each do |config|
        config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'gnu++17'

        definitions = config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] || ['$(inherited)']
        definitions = [definitions] unless definitions.is_a?(Array)
        unless definitions.include?('FMT_USE_CONSTEVAL=0')
          definitions << 'FMT_USE_CONSTEVAL=0'
        end
        config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = definitions

        cxxflags = config.build_settings['OTHER_CPLUSPLUSFLAGS'] || ['$(inherited)']
        cxxflags = [cxxflags] unless cxxflags.is_a?(Array)
        unless cxxflags.include?('-DFMT_USE_CONSTEVAL=0')
          cxxflags << '-DFMT_USE_CONSTEVAL=0'
        end
        config.build_settings['OTHER_CPLUSPLUSFLAGS'] = cxxflags
      end
    end

    # Xcode 26 + CocoaPods 1.14.3: for *static-library* xcframeworks (the
    # RunAnywhere RACommons / RABackend* binaries ship a `lib*.a`, not a
    # `.framework` bundle), CocoaPods writes an INCORRECT "[CP] Copy XCFrameworks"
    # output file list — it declares "<XCFrameworkName>.framework" instead of the
    # real "lib*.a" that the copy script actually stages. Xcode 26's stricter
    # build graph then fails the app link step with
    #   "Build input file cannot be found: .../XCFrameworkIntermediates/<Target>/librac_commons.a.
    #    Did you forget to declare this file as an output of a script phase ...?"
    # because the `-force_load .../librac_commons.a` (and `-l"rac_*"`) inputs have
    # no declared producer. Rewrite each output xcfilelist to point at the actual
    # static library, derived generically from the xcframework's Info.plist
    # (LibraryPath). Framework-type xcframeworks are left unchanged.
    pods_root = installer.sandbox.root.to_s
    Dir.glob(File.join(pods_root, 'Target Support Files', '*', '*-xcframeworks-output-files.xcfilelist')).each do |output_list|
      dir = File.dirname(output_list)
      target_name = File.basename(dir)
      input_list = File.join(dir, "#{target_name}-xcframeworks-input-files.xcfilelist")
      next unless File.exist?(input_list)

      xcframework_lines = File.readlines(input_list).map(&:strip).select { |l| l.end_with?('.xcframework') }
      next if xcframework_lines.empty?

      new_lines = []
      xcframework_lines.each do |raw|
        resolved = raw.gsub('${PODS_ROOT}', pods_root).gsub('$(PODS_ROOT)', pods_root)
        info_plist = File.join(resolved, 'Info.plist')
        next unless File.exist?(info_plist)

        plist = Xcodeproj::Plist.read_from_path(info_plist)
        library_path = (plist['AvailableLibraries'] || [])
                         .map { |slice| slice['LibraryPath'] }
                         .compact
                         .first
        next unless library_path

        new_lines << "${PODS_XCFRAMEWORKS_BUILD_DIR}/#{target_name}/#{library_path}"
      end

      next if new_lines.empty?

      desired = new_lines.join("\n") + "\n"
      if File.read(output_list) != desired
        File.write(output_list, desired)
        Pod::UI.puts "[RunAnywhere] Fixed XCFramework output file list for #{target_name}".green
      end
    end
  end
end
