default_platform(:ios)

platform :ios do
  # ─── Lanes ────────────────────────────────────────────────────────────

  desc "Build and sign the App Store IPA. Output at ../artifacts/Agora.ipa."
  lane :build_ipa do
    setup_lane_signing!
    build_release_ipa!
  end

  desc "Submit an already-built IPA to App Store Connect for review. " \
       "Set IPA_PATH to the IPA's location."
  lane :submit_release do
    ipa_path = ENV.fetch("IPA_PATH") do
      UI.user_error!("submit_release requires the IPA_PATH env var")
    end
    UI.user_error!("IPA not found at #{ipa_path}") unless File.exist?(ipa_path)
    submit_release_for_review!(ipa_path)
  end

  desc "Build, sign, and submit Agora to the App Store for review (single-step convenience)."
  lane :release do
    setup_lane_signing!
    build_release_ipa!
    # Use the IPA path set by build_app rather than recomputing it from
    # __dir__, which gets fragile across fastlane-relative paths.
    ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH]
    UI.user_error!("build_app did not set IPA_OUTPUT_PATH") unless ipa_path
    submit_release_for_review!(ipa_path)
  end

  desc "Submit an already-uploaded build for review (skip build/upload). " \
       "Use BUILD_NUMBER and VERSION env vars."
  lane :submit_only do
    submit_release_for_review!(nil)
  end

  # ─── Helpers ──────────────────────────────────────────────────────────

  def setup_lane_signing!
    # Create an ephemeral keychain so we never touch the login keychain.
    setup_ci

    api_key = build_api_key!

    # Fetch encrypted distribution cert + provisioning profile from the
    # shared certificates repo. --readonly: never mutate from CI.
    # Passing api_key makes match contact Apple's portal to verify the
    # cert is still valid for the team — fails fast on revoked/expired
    # certs instead of letting xcodebuild stumble later.
    match(type: "appstore", readonly: true, api_key: api_key)

    api_key
  end

  def build_api_key!
    # Build the API key hash inline. We avoid the app_store_connect_api_key
    # action because it sets APP_STORE_CONNECT_API_KEY_PATH (path to the .p8)
    # which collides with match's APP_STORE_CONNECT_API_KEY_PATH (path to a
    # JSON descriptor). Same env name, different formats.
    @api_key ||= {
      key_id: ENV.fetch("APP_STORE_CONNECT_API_KEY_ID"),
      issuer_id: ENV.fetch("APP_STORE_CONNECT_API_KEY_ISSUER_ID"),
      key: File.binread(ENV.fetch("ASC_KEY_PATH")),
      duration: 1200,
      in_house: false,
    }
  end

  def build_release_ipa!
    # Stamp build number from CI pipeline ID so every release is monotonically increasing.
    increment_build_number(
      xcodeproj: "App/App.xcodeproj",
      build_number: ENV.fetch("CI_PIPELINE_IID"),
    )

    # Marketing version is set externally (sed in CI) before this lane runs.

    build_app(
      project: "App/App.xcodeproj",
      scheme: "App",
      configuration: "Release",
      export_method: "app-store",
      output_directory: "../artifacts",
      output_name: "Agora.ipa",
      clean: true,
      # Override the Xcode project's Automatic signing for this build only.
      # Match has already installed the AppStore cert + profile into the
      # ephemeral keychain; tell xcodebuild to use them explicitly so it
      # doesn't also try to find an iOS Development cert (which we never
      # provision in CI).
      xcargs: [
        "CODE_SIGN_STYLE=Manual",
        "CODE_SIGN_IDENTITY='Apple Distribution'",
        "PROVISIONING_PROFILE_SPECIFIER='match AppStore spot.agora.app'",
        "DEVELOPMENT_TEAM=GZLTTH5DLM",
      ].join(" "),
      export_options: {
        method: "app-store",
        signingStyle: "manual",
        teamID: "GZLTTH5DLM",
        provisioningProfiles: {
          "spot.agora.app" => "match AppStore spot.agora.app",
        },
      },
    )
  end

  # If ipa_path is nil, deliver picks up the latest processed build for the
  # configured app version (used by the submit_only lane).
  def submit_release_for_review!(ipa_path)
    api_key = build_api_key!

    options = {
      api_key: api_key,
      submit_for_review: true,
      automatic_release: false,
      force: true,
      precheck_include_in_app_purchases: false,
      # Don't try to PATCH content rights on every submit — Apple's API
      # rejects updates to contentRightsDeclaration once the listing has
      # an established state. The values stay as set in the App Store
      # Connect UI / from a prior submission.
      submission_information: {
        export_compliance_uses_encryption: false,
      },
      skip_screenshots: true,
      # Keep skip_app_version_update=false: deliver needs to PATCH the
      # version's whatsNew (release notes) and platform-version metadata
      # before submit_for_review will accept the version.
      skip_app_version_update: false,
      skip_metadata: false,
      metadata_path: "./fastlane/metadata",
      run_precheck_before_submit: false,
    }
    options[:ipa] = ipa_path if ipa_path
    if ENV["BUILD_NUMBER"]
      options[:build_number] = ENV["BUILD_NUMBER"]
      options[:skip_binary_upload] = true
    end
    options[:app_version] = ENV["VERSION"] if ENV["VERSION"]

    deliver(**options)
  end
end
