# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

default_platform(:ios)

doc = <<-DESC
Build and optionally upload the app to App Store Connect.

Command-line options (all are optional):
- `version`: Override the marketing version string; otherwise read from version.all
- `dirty`: Pass `true` to allow building from a dirty git repo
- `branch`: The name of the branch to build from; default is current. Cannot be used with `dirty`
- `upload`: Pass `false` to prevent uploading to App Store Connect
- `public`: Pass `false` to prevent making the build available to TestFlight users (still uploads)
DESC

private_lane :ra_appstore_login do
  if !ENV['APP_STORE_CONNECT_API_KEY_KEY_ID'].to_s.empty?
    # this needs these environment variables set:
    # APP_STORE_CONNECT_API_KEY_KEY_ID,
    # APP_STORE_CONNECT_API_KEY_ISSUER_ID,
    # APP_STORE_CONNECT_API_KEY_KEY_FILEPATH
    app_store_connect_api_key
  end
end

private_lane :ra_reset_git_repo do |options|
  if !options[:dirty].nil? && options[:dirty]
    next
  end

  reset_git_repo(
    force: true,
    files: [
      "./OSX/assets.zip",
      "./OSX/Info_AppStore.plist",
      "./assets.zip",
      "./iOS/Info.plist",
      "./tvOS/Info.plist"
    ]
  )

  ensure_git_status_clean
  git_pull
  if !options[:branch].to_s.empty?
    branch = options[:branch].to_s
    sh("git checkout -b " + branch + " --track origin/" + branch)
  end
  sh("git log -1")
end

private_lane :ra_update_versions do |options|
  app_id = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)
  plat = lane_context[SharedValues::PLATFORM_NAME] == :mac ? "osx" : lane_context[SharedValues::PLATFORM_NAME].to_s
  username = CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
  team_id = CredentialsManager::AppfileConfig.try_fetch_value(:itc_team_id)

  begin
    latest_testflight_build_number(
      app_identifier: app_id,
      platform: plat,
      username: username,
      team_id: team_id
    )
    next_build_number = lane_context[SharedValues::LATEST_TESTFLIGHT_BUILD_NUMBER]
  rescue => ex
    next_build_number = 45
  end

  begin
    app_store_build_number(
      app_identifier: app_id,
      platform: plat,
      username: username,
      team_id: team_id,
      live: true
    )
    current_version_number = lane_context[SharedValues::LATEST_VERSION]
  rescue => ex
    current_version_number = "1.19.1"
  end
  UI.message("Current published version: #{current_version_number}")

  if options[:version].to_s.empty?
    version_file_path = File.expand_path("../../../../version.all", __FILE__)

    # Read the contents of the version.all file
    version_contents = File.read(version_file_path)

    # Use regex to extract the RARCH_VERSION or PACKAGE_VERSION
    rarch_version_match = version_contents.match(/RARCH_VERSION\s*=\s*"([^"]+)"/)
    package_version_match = version_contents.match(/PACKAGE_VERSION\s*"([^"]+)"/)

    # Select the desired version (RARCH_VERSION takes precedence)
    next_version_number = rarch_version_match ? rarch_version_match[1] : package_version_match[1]
  else
    next_version_number = options[:version]
  end
  UI.message("Extracted version: #{next_version_number}")

  require 'rubygems'

  if Gem::Version.new(current_version_number) >= Gem::Version.new(next_version_number)
    # if the version is already in the app store, Apple rules prevent
    # uploading more builds on that version
    version_array = current_version_number.split(".").map(&:to_i)
    version_array[-1] += 1
    next_version_number = version_array.join(".")
    UI.message("Bumping to version: #{next_version_number}")
  end

  # can't use update_build_number/agvtool to update this as it
  # doesn't deal with multiple projects in the same folder
  update_info_plist(
    plist_path: options[:plist_path],
    block: proc do |plist|
      plist["CFBundleVersion"] = (next_build_number + 1).to_s
      plist["CFBundleShortVersionString"] = next_version_number
    end
  )
end

private_lane :ra_update_signing do |options|
  sdk = lane_context[SharedValues::PLATFORM_NAME] == :ios ? "iphoneos*" : "appletvos*"
  app_id = CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier)

  update_code_signing_settings(
    targets: options[:app_target],
    use_automatic_signing: false,
    path: "RetroArch_iOS13.xcodeproj",
    team_id: CredentialsManager::AppfileConfig.try_fetch_value(:team_id),
    code_sign_identity: "iPhone Distribution",
    sdk: sdk,
    profile_name: options[:app_profile]
  )
  update_code_signing_settings(
    targets: options[:ext_target],
    use_automatic_signing: false,
    path: "RetroArch_iOS13.xcodeproj",
    team_id: CredentialsManager::AppfileConfig.try_fetch_value(:team_id),
    bundle_identifier: app_id + "." + options[:ext_id],
    code_sign_identity: "iPhone Distribution",
    sdk: sdk,
    profile_name: options[:ext_profile]
  )
end

private_lane :ra_build_app do |options|
  build_app(
    workspace: "RetroArch.xcworkspace",
    scheme: options[:scheme],
    xcconfig: options[:xcconfig],
    xcodebuild_formatter: 'xcbeautify --renderer github-actions',
    buildlog_path: "buildlog",
    export_method: "app-store",
    export_options: {
      provisioningProfiles: options[:provisioningProfiles]
    }
  )
end

private_lane :ra_upload_to_testflight do |options|
  if options[:upload].nil? or options[:upload]
    info = last_git_commit
    short_hash = info[:abbreviated_commit_hash]
    upload_to_testflight(
      distribute_external: (options[:public].nil? || options[:public]),
      groups: options[:public].nil? || options[:public] ? ['Invaders', 'Patreons'] : [],
      changelog: "Rebuild frontend for commit #{short_hash}"
    )
  end
end

platform :mac do
  desc doc
  lane :build do |options|
    options[:plist_path] = "OSX/Info_AppStore.plist"

    ra_appstore_login

    ra_reset_git_repo(options)

    ra_update_versions(options)

    ra_build_app(
      scheme: "RetroArch AppStore",
      provisioningProfiles: {
        "com.libretro.dist.RetroArch" => "macOS App Store"
      }
    )

    ra_upload_to_testflight(options)
  end
end

platform :ios do
  desc doc
  lane :build do |options|
    options[:plist_path] = "iOS/Info.plist"

    ra_appstore_login

    ra_reset_git_repo(options)

    ra_update_versions(options)

    ra_update_signing(
      app_target: "RetroArchiOS",
      app_profile: "App Store Distribution",
      ext_target: "RetroArchWidgetExtensionExtension",
      ext_id: "RetroArchWidgetExtension",
      ext_profile: "App Store Widget"
    )

    ra_build_app(
      scheme: "RetroArch iOS Release",
      xcconfig: "iOS/AppStore.xcconfig",
      provisioningProfiles: {
        "com.libretro.dist.RetroArch" => "App Store Distribution",
        "com.libretro.dist.RetroArch.RetroArchWidgetExtension" => "App Store Widget"
      }
    )

    ra_upload_to_testflight(options)
  end
end

platform :appletvos do
  desc doc
  lane :build do |options|
    options[:plist_path] = "tvOS/Info.plist"

    ra_appstore_login

    ra_reset_git_repo(options)

    ra_update_versions(options)

    ra_update_signing(
      app_target: "RetroArchTV",
      app_profile: "tvOS App Store",
      ext_target: "RetroArchTopShelfExtension",
      ext_id: "RetroArchTopShelfExtension",
      ext_profile: "tvOS Top Shelf App Store"
    )

    ra_build_app(
      scheme: "RetroArch tvOS Release",
      xcconfig: "iOS/AppStore.xcconfig",
      provisioningProfiles: {
        "com.libretro.dist.RetroArch" => "tvOS App Store",
        "com.libretro.dist.RetroArch.RetroArchTopShelfExtension" => "tvOS Top Shelf App Store"
      }
    )

    ra_upload_to_testflight(options)
  end
end
