#!/usr/bin/env ruby
# frozen_string_literal: true
#
# Inject the Share Extension target into the Capacitor-generated Xcode project.
#
# WHY A SCRIPT: `npx cap add ios` scaffolds mobile/ios/App from a template that knows nothing about our
# extension, and Codemagic runs on a fresh checkout every time, so the target has to be (re)created on each
# build. This uses the `xcodeproj` gem, which ships with CocoaPods (already installed for `pod install`),
# so there is no extra dependency to add.
#
# WHAT IT WIRES:
#   * a new app-extension target "ShareExtension" (bundle id <app>.share) whose sources are our
#     ShareViewController.swift + Info.plist, copied in from mobile/ios-share/
#   * the App Group entitlement on BOTH the App target and the extension (the only storage both processes
#     can see), via the two .entitlements files
#   * the extension embedded into the app ("Embed App Extensions" phase) and set as a build dependency
#
# Idempotent: if the target already exists it is removed and rebuilt, so re-runs never duplicate it.

require 'xcodeproj'
require 'fileutils'

ROOT       = File.expand_path('..', __dir__)                          # repo/mobile (this script is in mobile/scripts)
PROJECT    = File.join(ROOT, 'ios', 'App', 'App.xcodeproj')
SRC_DIR    = File.join(ROOT, 'ios-share')                              # our checked-in extension sources
APP_DIR    = File.join(ROOT, 'ios', 'App')
EXT_NAME   = 'ShareExtension'
EXT_DIR    = File.join(APP_DIR, EXT_NAME)
APP_TARGET = 'App'
APP_BUNDLE = ENV.fetch('BUNDLE_ID', 'com.bizgaze.connect')
EXT_BUNDLE = "#{APP_BUNDLE}.share"

abort "xcodeproj not found at #{PROJECT}" unless File.directory?(PROJECT)

project = Xcodeproj::Project.open(PROJECT)
app = project.targets.find { |t| t.name == APP_TARGET }
abort "App target not found" unless app

# ── Clean any previous injection so this is idempotent ──────────────────────────────────────────────
project.targets.select { |t| t.name == EXT_NAME }.each do |t|
  t.build_configuration_list&.build_configurations&.each { |c| c.remove_from_project }
  t.remove_from_project
end
if (grp = project.main_group.children.find { |g| g.respond_to?(:display_name) && g.display_name == EXT_NAME })
  grp.remove_from_project
end

# ── Copy our sources into the app project so paths inside the .xcodeproj are stable ──────────────────
FileUtils.mkdir_p(EXT_DIR)
%w[ShareViewController.swift Info.plist ShareExtension.entitlements].each do |f|
  FileUtils.cp(File.join(SRC_DIR, f), File.join(EXT_DIR, f))
end

# The App Group entitlement for the MAIN app. MERGE, don't overwrite: the push-notifications plugin may
# already have written App/App.entitlements (aps-environment), and clobbering it would break push. We add
# the app-group array into whatever is there (or create the file if it's absent).
APP_GROUP = 'group.com.bizgaze.connect'
app_ent_path = File.join(APP_DIR, 'App', 'App.entitlements')
app_ent = File.exist?(app_ent_path) ? (Xcodeproj::Plist.read_from_path(app_ent_path) || {}) : {}
groups = app_ent['com.apple.security.application-groups'] || []
groups << APP_GROUP unless groups.include?(APP_GROUP)
app_ent['com.apple.security.application-groups'] = groups
Xcodeproj::Plist.write_to_path(app_ent, app_ent_path)
puts "App entitlements: app-group ensured (kept #{(app_ent.keys - ['com.apple.security.application-groups']).join(', ')})"

# ── Create the extension target ──────────────────────────────────────────────────────────────────────
# deployment_target can be nil when it's only set at the project level — fall back so we never create a
# target with an empty minimum-OS (which Xcode then flags).
deployment = app.deployment_target || project.build_configurations.first&.build_settings&.[]('IPHONEOS_DEPLOYMENT_TARGET') || '15.0'
ext = project.new_target(
  :app_extension, EXT_NAME, :ios,
  deployment, project.products_group, :swift
)

# Source file + resources
group = project.main_group.new_group(EXT_NAME, "#{EXT_NAME}")
swift_ref = group.new_reference(File.join(EXT_DIR, 'ShareViewController.swift'))
ext.add_file_references([swift_ref])

# Build settings for every configuration (Debug/Release)
ext.build_configurations.each do |cfg|
  s = cfg.build_settings
  s['PRODUCT_BUNDLE_IDENTIFIER']        = EXT_BUNDLE
  s['PRODUCT_NAME']                     = '$(TARGET_NAME)'
  s['INFOPLIST_FILE']                   = "#{EXT_NAME}/Info.plist"
  s['CODE_SIGN_ENTITLEMENTS']           = "#{EXT_NAME}/ShareExtension.entitlements"
  s['IPHONEOS_DEPLOYMENT_TARGET']       = deployment
  s['SWIFT_VERSION']                    = '5.0'
  s['TARGETED_DEVICE_FAMILY']           = '1,2'
  s['GENERATE_INFOPLIST_FILE']          = 'NO'
  s['SKIP_INSTALL']                     = 'YES'
  s['CODE_SIGN_STYLE']                  = 'Manual'
  s['MARKETING_VERSION']                = '1.0'
  s['CURRENT_PROJECT_VERSION']          = ENV.fetch('BUILD_NUMBER', '1')
  s['LD_RUNPATH_SEARCH_PATHS']          = '$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks'
end

# ── App Group entitlement on the MAIN app target too ─────────────────────────────────────────────────
app.build_configurations.each do |cfg|
  cfg.build_settings['CODE_SIGN_ENTITLEMENTS'] = 'App/App.entitlements'
end

# ── Embed the extension into the app + depend on it ──────────────────────────────────────────────────
app.add_dependency(ext)
embed = app.build_phases.find { |p| p.respond_to?(:symbol_dst_subfolder_spec) && p.symbol_dst_subfolder_spec == :plug_ins }
embed ||= begin
  phase = app.new_copy_files_build_phase('Embed App Extensions')
  phase.symbol_dst_subfolder_spec = :plug_ins
  phase
end
appex = ext.product_reference
build_file = embed.add_file_reference(appex)
build_file.settings = { 'ATTRIBUTES' => ['RemoveHeadersOnCopy'] }

# ── Bundle the custom notification sound (notif.wav) into the App target ─────────────────────────────
# ios-patch.sh copied it to App/App/notif.wav. Add it as a resource so it ships in the bundle root where
# APNs can find it (the server sends sound:'notif.wav'). Tolerant: never fail the build over the sound.
begin
  snd_path = File.join(APP_DIR, 'App', 'notif.wav')
  if File.exist?(snd_path)
    grp = project.main_group.find_subpath('App', false) || project.main_group
    already = app.resources_build_phase.files.any? { |bf| bf.file_ref && bf.file_ref.respond_to?(:display_name) && bf.file_ref.display_name == 'notif.wav' }
    unless already
      snd_ref = grp.new_reference(snd_path)
      app.resources_build_phase.add_file_reference(snd_ref)
    end
    puts "Notification sound bundled into App resources: notif.wav"
  else
    puts "  (notif.wav not in project — sound not bundled)"
  end
rescue => e
  puts "  (notif.wav bundling skipped: #{e.message})"
end

project.save
puts "Share Extension injected: #{EXT_NAME} (#{EXT_BUNDLE}) embedded in #{APP_TARGET}"
