fastlane_version '2.71.0'
fastlane_require 'aws-sdk-s3'
fastlane_require 'erb'
fastlane_require 'json'
fastlane_require 'pathname'

skip_docs

configured = false
is_build_pr = false

# Executes before anything else use to setup the script
before_all do
  ENV['SPACESHIP_SKIP_2FA_UPGRADE'] = '1'

  is_build_pr = ENV['BUILD_PR'] == 'true'
  if is_build_pr && ENV['CI'] == 'true'
    ENV['BRANCH_TO_BUILD'] = ENV['GITHUB_REF_NAME']
  end

  if ENV['CI'] != 'true'
    # Raises an error is git is not clean
    if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
      ensure_git_status_clean
    end

    # Block to ensure we are on the right branch
    branch = ENV['BRANCH_TO_BUILD'] || ENV['GIT_BRANCH']
    begin
      ensure_git_branch(
          branch: branch
      )
    rescue
      sh "git checkout #{branch}"
      UI.success("Using branch \"#{branch}\"")
    end

    # If we are going to commit changes to git create a separate branch
    # so no changes are done in the branch that is being built
    if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
      local_branch = ENV['GIT_LOCAL_BRANCH'] || 'build'
      sh "git checkout -b #{local_branch}"
      UI.success("Creating branch \"#{local_branch}\"")
    end
  end
end

after_all do |lane|
  if ENV['CI'] != 'true'
    if ENV['RESET_GIT_BRANCH'] == 'true'
      branch = ENV['BRANCH_TO_BUILD'] || 'main'
      package_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta'
      beta_dir = '../android/app/src/main/java/com/mattermost/rnbeta'
      release_dir = "../android/app/src/main/java/#{package_id.gsub '.', '/'}"

      if beta_dir != release_dir
        sh "rm -rf #{release_dir}"
      end

      reset_git_repo(
          force: true,
          skip_clean: true
      )
      sh "git checkout #{branch}"

      if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
        local_branch = ENV['GIT_LOCAL_BRANCH'] || 'build'
        sh "git branch -D #{local_branch}"
        UI.success("Deleted working branch \"#{local_branch}\"")
        if lane.to_s == 'build_pr'
          sh 'git checkout main'
          ## Remove the branch for the PR
          sh "git branch -D #{branch}"
          UI.success("Deleted PR branch \"#{branch}\"")
        end
      end
    end
  end
end

desc 'Increment version number for both Android and iOS'
lane :set_app_version do
  version_number = ENV['VERSION_NUMBER']
  unless version_number.nil? || version_number.empty?
    package = load_config_json('../package.json')
    package['version'] = version_number
    save_json_as_file('../package.json', package)

    lock = load_config_json('../package-lock.json')
    lock['version'] = version_number
    save_json_as_file('../package-lock.json', lock)

    android_set_version_name(
        gradle_file: './android/app/build.gradle',
        version_name: version_number
    )

    increment_version_number(
        xcodeproj: './ios/Mattermost.xcodeproj',
        version_number: version_number
    )

    if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
      msg = ENV['INCREMENT_VERSION_NUMBER_MESSAGE'] || 'Bump app version number to'
      commit_message = "#{msg} #{version_number.to_s}"
      build_folder_path = Dir[File.expand_path('..')].first
      repo_path = (sh "git -C #{build_folder_path} rev-parse --show-toplevel").strip
      git_dirty_files = (sh "git -C #{repo_path} diff --name-only HEAD").split(" ").join(' ')

      unless git_dirty_files.empty?
        sh "git -C #{repo_path} commit -m \"#{commit_message}\" #{git_dirty_files}"
        UI.success("Successfully committed \"#{git_dirty_files}\" 💾.")
      end
    end
  end
end

desc 'Increments the build number for both Android and iOS'
lane :set_app_build_number do
  ## set the build number for both platforms
  # use the one for iOS if no env variable set
  if ENV['INCREMENT_BUILD_NUMBER'] === 'true'
    build_number = ENV['BUILD_NUMBER'] || (get_build_number(xcodeproj: './ios/Mattermost.xcodeproj').to_i + 1)
    increment_build_number(
        xcodeproj: './ios/Mattermost.xcodeproj',
        build_number: build_number
    )
    android_set_version_code(
        gradle_file: './android/app/build.gradle',
        version_code: build_number
    )


    if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
      msg = ENV['INCREMENT_BUILD_NUMBER_MESSAGE'] || 'Bump app build number to'
      commit_message = "#{msg} #{build_number.to_s}"
      build_folder_path = Dir[File.expand_path('..')].first
      repo_path = (sh "git -C #{build_folder_path} rev-parse --show-toplevel").strip
      git_dirty_files = (sh "git -C #{repo_path} diff --name-only HEAD").split(" ").join(' ')

      unless git_dirty_files.empty?
        sh "git -C #{repo_path} commit -m \"#{commit_message}\" #{git_dirty_files}"
        UI.success("Successfully committed \"#{git_dirty_files}\" 💾.")
      end
    end
  end
end

desc 'Increments version and build number for both Android and iOS'
lane :set_app_version_build do
  set_app_version
  set_app_build_number
end

desc 'Configure the app before building'
lane :configure do
  json = load_config_json('../dist/assets/config.json')

  # Set the Segment API Key
  unless ENV['RUDDER_API_KEY'].nil? || ENV['RUDDER_API_KEY'].empty?
    json['RudderApiKey'] =  ENV['RUDDER_API_KEY']
  end

  # Configure Sentry if enabled
  if ENV['SENTRY_ENABLED'] == 'true'
    json['SentryEnabled'] = true
    json['SentryOrg'] = ENV['SENTRY_ORG']
    json['SentryProjectIos'] = ENV['SENTRY_PROJECT_IOS']
    json['SentryProjectAndroid'] = ENV['SENTRY_PROJECT_ANDROID']
    json['SentryDsnIos'] = ENV['SENTRY_DSN_IOS']
    json['SentryDsnAndroid'] = ENV['SENTRY_DSN_ANDROID']
  end

  # Configure show app review
  if ENV['SHOW_REVIEW'] == 'true'
    json['ShowReview'] = true
  end

  # Configure Show Onboarding
  if ENV['SHOW_ONBOARDING'] == 'true'
    json['ShowOnboarding'] = true
  end

  # Collect network request information with different request group (notifications, login, cold start, etc)
  if ENV['COLLECT_NETWORK_METRICS'] == 'true'
    json['CollectNetworkMetrics'] = true
  end

  # Configure the auth schemes
  auth_scheme = ENV['APP_AUTH_SCHEME'].to_s.empty? ? 'mmauth' : ENV['APP_AUTH_SCHEME']
  auth_scheme_dev = ENV['APP_AUTH_SCHEME_BETA'].to_s.empty? ? 'mmauthbeta' : ENV['APP_AUTH_SCHEME_BETA']
  json["AuthUrlScheme"] = auth_scheme.end_with?('://') ? auth_scheme : "#{auth_scheme}://"
  json["AuthUrlSchemeDev"] = auth_scheme_dev.end_with?('://') ? auth_scheme_dev : "#{auth_scheme_dev}://"

  # Save the config.json file
  save_json_as_file('../dist/assets/config.json', json)

  configured = true
end

desc 'Set Sentry upload properties'
lane :link_sentry do |options|
  if ENV['SENTRY_ENABLED'] == 'true'
    os_type = options[:os_type].downcase
    if os_type == 'ios'
      project_dir = 'ios/'
      sentry_project = ENV['SENTRY_PROJECT_IOS']
    elsif os_type == 'android'
      project_dir = 'android/'
      sentry_project = ENV['SENTRY_PROJECT_ANDROID']
    end
    url = ENV['SENTRY_URL'] || 'https://sentry.io'
    File.open("../#{project_dir}sentry.properties", 'w+') do |f|
      UI.message('Creating sentry.properties from environment')
      f.write(
        "defaults.url=#{url}\n"\
        "defaults.org=#{ENV['SENTRY_ORG']}\n"\
        "defaults.project=#{sentry_project}\n"\
        "auth.token=#{ENV['SENTRY_AUTH_TOKEN']}\n"
      )
    end
  else
    UI.message('Not creating sentry.properties because Sentry is disabled')
  end
end

desc 'Upload file to s3'
lane :upload_file_to_s3 do |options|
  os_type = options[:os_type].downcase
  extensions = os_type == "android" ? ["*.apk", "*.aab"] : ["*.ipa"]
  build_folder_path = Dir[File.expand_path('..')].first
  files = []

  unless options[:file].nil? || options[:file].empty?
    files.push("#{build_folder_path}/#{options[:file]}")
  else
    extensions.each do |extension|
      files.push(*Dir.glob("#{build_folder_path}/#{extension}").select { |f| File.file? f})
    end
  end

  unless ENV['AWS_BUCKET_NAME'].nil? || ENV['AWS_BUCKET_NAME'].empty? || ENV['AWS_REGION'].nil? || ENV['AWS_REGION'].empty? || files.length == 0
    version_number = ''
    build_number = ''
    pr_file = ''
    plist_file = ''

    if is_build_pr
      pr_file = File.basename(files.first)
      plist_file = "#{File.basename(files.first, '.*')}.plist"
    else
      version_number = os_type == "android" ?
        android_get_version_name(gradle_file: './android/app/build.gradle') :
        get_version_number(xcodeproj: './ios/Mattermost.xcodeproj', target: 'Mattermost')
      build_number = os_type == "android" ?
        android_get_version_code(gradle_file: './android/app/build.gradle') :
        get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
    end

    s3_region = ENV['AWS_REGION']
    s3_bucket_name = ENV['AWS_BUCKET_NAME']
    s3_folder = is_build_pr ?
      "#{ENV['AWS_FOLDER_NAME']}/#{ENV['BRANCH_TO_BUILD']}" :
      "#{ENV['AWS_FOLDER_NAME']}/#{version_number}/#{build_number}"

    s3 = Aws::S3::Resource.new(region: s3_region)
    s3_bucket = s3.bucket(s3_bucket_name)
    mutex = Mutex.new
    threads = []
    file_number = 0
    total_files = files.length
    links = []
    total_files.times do |i|
      threads[i] = Thread.new {
        until files.empty?
          mutex.synchronize do
            file_number += 1
            Thread.current["file_number"] = file_number
          end
          file = files.pop rescue nil
          next unless file

          filename = File.basename(file)
          puts "[#{Thread.current["file_number"]}/#{total_files}] #{filename} uploading..."
          s3_file = s3_bucket.object("#{s3_folder}/#{filename}")
          s3_file.upload_file("#{file}")
          links.push("https://#{s3_bucket_name}/#{s3_folder}/#{filename}")
        end
      }
    end
    threads.each { |t| t.join }

    if is_build_pr
      if os_type == 'android'
        install_url = "https://#{s3_bucket_name}/#{s3_folder}/#{pr_file}"
      elsif os_type == 'ios'
        current_build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
        plist_template = File.read('plist.erb')
        plist_body = ERB.new(plist_template).result(binding)

        plist_obj = s3_bucket.object("#{s3_folder}/#{plist_file}")
        plist_obj.put(body: plist_body)

        install_url = "itms-services://?action=download-manifest&url=https://#{s3_bucket_name}/#{s3_folder}/#{plist_file}"
      end

      qa_build_message({
                            :os_type => os_type,
                            :install_url => install_url
                        })
    end

    if options[:file] == 'Mattermost-simulator-x86_64.app.zip'
      pretext = '#### New iOS build for VM/Simulator'
      msg = "Download link: #{links.first}"
      send_message_to_mattermost({
                                      :version_number => version_number,
                                      :build_number => build_number,
                                      :pretext => pretext,
                                      :title => '',
                                      :thumb_url => 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png',
                                      :msg => msg,
                                      :default_payloads => [:git_branch, :last_git_commit_hash],
                                      :success => true,
                                  })
    end

    UI.message("S3 public paths:\n#{links.join("\n")}")
  end
end

desc 'Create GitHub release'
lane :github do
  tag = ENV['GITHUB_REF_NAME'] || ENV['TAG']

  if tag
    version = android_get_version_name(gradle_file: './android/app/build.gradle')
    build = android_get_version_code(gradle_file: './android/app/build.gradle')
    changelog = File.read("metadata/changelog")
    android = [
      "    * [Mattermost arm64-v8a](https://releases.mattermost.com/mattermost-mobile/#{version}/#{build}/Mattermost-arm64-v8a.apk)",
      "    * [Mattermost armeabi-v7a](https://releases.mattermost.com/mattermost-mobile/#{version}/#{build}/Mattermost-armeabi-v7a.apk)",
      "    * [Mattermost x86](https://releases.mattermost.com/mattermost-mobile/#{version}/#{build}/Mattermost-x86.apk)",
      "    * [Mattermost x86_64](https://releases.mattermost.com/mattermost-mobile/#{version}/#{build}/Mattermost-x86_64.apk)",
    ]
    changelog.concat("* Android\n#{android.join("\n")}\n")
    changelog.concat("* iOS\n    * [Mattermost](https://releases.mattermost.com/mattermost-mobile/#{version}/#{build}/Mattermost.ipa)")

    github_release = set_github_release(
      repository_name: "mattermost/mattermost-mobile",
      api_token: ENV["GITHUB_TOKEN"],
      name: "Mobile Version #{version}",
      tag_name: tag,
      description: changelog,
      upload_assets: ["./Mattermost-unsigned.ipa", "./Mattermost-unsigned.apk"],
      is_draft: true
    )
  end
end

platform :ios do
  before_all do
    if ENV['CI'] == 'true'
      setup_ci
    end
  end

  desc 'Get iOS match profiles'
  lane :certs do
    if !ENV['IOS_API_KEY_ID'].nil? && !ENV['IOS_API_KEY_ID'].empty?
      api_key = get_apple_api_key()
      match(
          api_key: api_key,
          type: ENV['MATCH_TYPE'] || 'adhoc'
      )
    end
  end

  desc 'Build iOS app'
  lane :build do
    unless configured
      configure
    end
    update_identifiers
    replace_assets
    link_sentry({:os_type => "ios"})
    build_ios
    upload_file_to_s3({:os_type => "ios"})
  end

  desc 'Build an unsigned ipa'
  lane :unsigned do
    UI.success('Building unsigned iOS app')

    ENV['APP_NAME'] = 'Mattermost'
    ENV['REPLACE_ASSETS'] = 'true'
    ENV['BUILD_FOR_RELEASE'] = 'true'
    ENV['APP_SCHEME'] = 'mattermost'

    update_identifiers
    replace_assets

    build_ios_unsigned_or_simulator(
      more_xc_args: "-sdk iphoneos CODE_SIGNING_ALLOWED=NO",
      rel_build_dir: "Release-iphoneos",
      output_file: "Mattermost-unsigned.ipa",
    )
  end

  lane :simulator do
    UI.success('Building iOS app for simulator')

    output_file = "Mattermost-simulator-x86_64.app.zip"

    build_ios_unsigned_or_simulator(
      more_xc_args: "-sdk iphonesimulator -arch x86_64",
      rel_build_dir: "Release-iphonesimulator",
      output_file: output_file,
    )

    upload_file_to_s3({
      :os_type => "ios",
      :file => output_file
    })
  end

  lane :update_identifiers do
    # Set the name for the app and share extension
    app_name =  ENV['APP_NAME'] || 'Mattermost Beta'
    update_info_plist(
        xcodeproj: './ios/Mattermost.xcodeproj',
        plist_path: 'Mattermost/Info.plist',
        display_name: app_name
    )

    update_info_plist(
      xcodeproj: './ios/Mattermost.xcodeproj',
      plist_path: 'MattermostShare/Info.plist',
      display_name: app_name
    )

    # Set the notification service extension bundle identifier
    notification_bundle_id = ENV['NOTIFICATION_SERVICE_IDENTIFIER'] || 'com.mattermost.rnbeta.NotificationService'
    update_app_identifier(
        xcodeproj: './ios/Mattermost.xcodeproj',
        plist_path: 'NotificationService/Info.plist',
        app_identifier: notification_bundle_id
    )

    find_replace_string(
        path_to_file: './ios/Mattermost.xcodeproj/project.pbxproj',
        old_string: 'com.mattermost.rnbeta.NotificationService',
        new_string: notification_bundle_id
    )

    # Set the share extension bundle identifier
    extension_bundle_id = ENV['EXTENSION_APP_IDENTIFIER'] || 'com.mattermost.rnbeta.MattermostShare'
    update_app_identifier(
        xcodeproj: './ios/Mattermost.xcodeproj',
        plist_path: 'MattermostShare/Info.plist',
        app_identifier: extension_bundle_id
    )

    find_replace_string(
        path_to_file: './ios/Mattermost.xcodeproj/project.pbxproj',
        old_string: 'com.mattermost.rnbeta.MattermostShare',
        new_string: extension_bundle_id
    )

    # Set the app bundle id
    app_bundle_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta'
    update_app_identifier(
        xcodeproj: './ios/Mattermost.xcodeproj',
        plist_path: 'Mattermost/Info.plist',
        app_identifier: app_bundle_id
    )

    find_replace_string(
        path_to_file: './ios/Mattermost.xcodeproj/project.pbxproj',
        old_string: 'com.mattermost.rnbeta',
        new_string: app_bundle_id
    )

    # Set the deep link prefix
    app_scheme = ENV['APP_SCHEME'] || 'mattermost'
    app_auth_scheme = get_auth_scheme
    UI.success "Update auth scheme to #{app_auth_scheme} #{ENV['BETA_BUILD']} authScheme #{ENV['APP_AUTH_SCHEME']} beta #{ENV['APP_AUTH_SCHEME_BETA']}"
    update_info_plist(
        xcodeproj: './ios/Mattermost.xcodeproj',
        plist_path: 'Mattermost/Info.plist',
        block: proc do |plist|
          urlScheme = plist["CFBundleURLTypes"].find{|scheme| scheme["CFBundleURLName"] == "com.mattermost"}
          urlScheme[:CFBundleURLSchemes] = [app_scheme, app_auth_scheme]
        end
    )

    # If set update the development team
    unless ENV['FASTLANE_TEAM_ID'].nil? || ENV['FASTLANE_TEAM_ID'].empty?
    update_project_team(
        path: './ios/Mattermost.xcodeproj',
        teamid: ENV['FASTLANE_TEAM_ID']
    )
    end

    # Set the ICloud container
    icloud_container = ENV['IOS_ICLOUD_CONTAINER'] || 'iCloud.com.mattermost.rnbeta'
    update_icloud_container_identifiers(
        entitlements_file: './ios/Mattermost/Mattermost.entitlements',
        icloud_container_identifiers: [icloud_container]
    )

    # Set the app group id to share data between the app and the extension
    app_group_id = ENV['IOS_APP_GROUP'] || 'group.com.mattermost.rnbeta'
    update_app_group_identifiers(
        entitlements_file: './ios/Mattermost/Mattermost.entitlements',
        app_group_identifiers: [app_group_id]
    )

    update_info_plist(
      xcodeproj: './ios/Mattermost.xcodeproj',
      plist_path: 'Mattermost/Info.plist',
      block: proc do |plist|
        plist["AppGroupIdentifier"] = app_group_id
      end
    )

    update_app_group_identifiers(
        entitlements_file: './ios/NotificationService/NotificationService.entitlements',
        app_group_identifiers: [app_group_id]
    )

    update_info_plist(
      xcodeproj: './ios/Mattermost.xcodeproj',
      plist_path: 'NotificationService/Info.plist',
      block: proc do |plist|
        plist["AppGroupIdentifier"] = app_group_id
      end
    )

    update_app_group_identifiers(
      entitlements_file: './ios/MattermostShare/MattermostShare.entitlements',
      app_group_identifiers: [app_group_id]
    )

    update_info_plist(
      xcodeproj: './ios/Mattermost.xcodeproj',
      plist_path: 'MattermostShare/Info.plist',
      block: proc do |plist|
        plist["AppGroupIdentifier"] = app_group_id
      end
    )

    # Sync the provisioning profiles using match
    if ENV['SYNC_PROVISIONING_PROFILES'] == 'true'
      if !ENV['MATCH_PASSWORD'].nil? && !ENV['MATCH_PASSWORD'].empty?
        match(type: ENV['MATCH_TYPE'] || 'adhoc')
      end
      if !ENV['IOS_API_KEY_ID'].nil? && !ENV['IOS_API_KEY_ID'].empty?
        api_key = get_apple_api_key()
        match(
            api_key: api_key,
            type: ENV['MATCH_TYPE'] || 'adhoc'
        )
      end
    end
  end

  lane :replace_assets do
    if ENV['REPLACE_ASSETS'] == 'true'
      sh 'cp -R ../dist/assets/release/icons/ios/* ../ios/Mattermost/Images.xcassets/AppIcon.appiconset/'
      sh 'cp -R ../dist/assets/release/splash_screen/ios/LaunchScreen.storyboard ../ios/SplashScreenResource/LaunchScreen.storyboard'
      sh 'cp -R ../dist/assets/release/splash_screen/ios/SplashBackground.imageset ../ios/Mattermost/Images.xcassets/'
      sh 'cp -R ../dist/assets/release/splash_screen/ios/SplashIcon.imageset ../ios/Mattermost/Images.xcassets/'
    end

    app_name =  ENV['APP_NAME'] || 'Mattermost Beta'
    localization_base_path = '../dist/assets/i18n/'
    Dir.glob('*.json', base: localization_base_path) do |item|
      localization_file = File.read(localization_base_path + item)
      json = JSON.parse(localization_file)

      plist_strings = ''
      localized_strings = ''
      json.each do |key, value|
        unless value.nil? || value.empty?
          if key.match?('mobile.ios.plist')
            plist_strings.concat("#{key.split('.').last} = \"#{value}\";\n")
          else
            value.gsub!('\\', '\\\\\\\\') # How to replace backslash with double backslash https://stackoverflow.com/a/6209532
            value.gsub!('"', '\"')
            localized_strings.concat("\"#{key}\" = \"#{value}\";\n")
          end
        end
      end

      plist_strings.gsub!('{applicationName}', "#{app_name}")
      localized_strings.gsub!('{applicationName}', "#{app_name}")

      language = item.split('.').first
      project_localization_path = "../ios/Mattermost/i18n/#{language}.lproj"
      FileUtils.mkdir_p project_localization_path
      File.write("#{project_localization_path}/InfoPlist.strings", plist_strings)
      File.write("#{project_localization_path}/Localizable.strings", localized_strings)
    end
  end

  lane :deploy do |options|
    ipa_path = options[:file]

    unless ipa_path.nil?
      submit_to_testflight(ipa_path)
    end
  end

  error do |lane, exception|
    version = get_version_number(xcodeproj: './ios/Mattermost.xcodeproj', target: 'Mattermost')
    build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
    send_message_to_mattermost({
                                   :version_number => version,
                                   :build_number => build_number,
                                   :pretext => '',
                                   :title => 'Unsuccessful Build',
                                   :thumb_url => 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png',
                                   :msg => exception.message,
                                   :default_payloads => [:lane],
                                   :success => false
                               })
  end

  def setup_code_signing
    update_code_signing_settings(
      use_automatic_signing: false,
      path: './ios/Mattermost.xcodeproj'
    )

    ENV['MATCH_APP_IDENTIFIER'].split(',').each do |id|
      target = 'Mattermost'
      if id.include? 'NotificationService'
        target = 'NotificationService'
      elsif id.include? 'MattermostShare'
        target = 'MattermostShare'
      end

      profile = "sigh_#{id}_#{ENV['MATCH_TYPE']}"
      config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug'

      update_project_provisioning(
          xcodeproj: './ios/Mattermost.xcodeproj',
          profile: ENV["#{profile}_profile-path"], # optional if you use sigh
          target_filter: ".*#{target}$", # matches name or type of a target
          build_configuration: config_mode,
          code_signing_identity: 'iPhone Distribution' # optionally specify the codesigning identity
      )
    end
  end

  def build_ios
    app_name =  ENV['APP_NAME'] || 'Mattermost Beta'
    app_name_sub = app_name.gsub(" ", "_")
    config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug'
    method = ENV['IOS_BUILD_EXPORT_METHOD'].nil? || ENV['IOS_BUILD_EXPORT_METHOD'].empty? ? 'ad-hoc' : ENV['IOS_BUILD_EXPORT_METHOD']

    # Need to add xcargs to only notification and share extensions
    xcargs = ENV['SENTRY_ENABLED'] == 'true' ? "SENTRY_DSN_IOS='#{ENV['SENTRY_DSN_IOS']}' SENTRY_ENABLED='#{ENV['SENTRY_ENABLED']}'" : ''

    setup_code_signing

    gym(
        clean: true,
        scheme: 'Mattermost',
        configuration: config_mode,
        workspace: './ios/Mattermost.xcworkspace',
        export_method: method,
        skip_profile_detection: true,
        output_name: "#{app_name_sub}.ipa",
        export_xcargs: "-allowProvisioningUpdates",
        export_options: {
            signingStyle: 'manual',
            iCloudContainerEnvironment: 'Production'
        },
        xcargs: xcargs
    )
  end

  def build_ios_unsigned_or_simulator(more_xc_args:, rel_build_dir:, output_file:)
    root_dir = Dir[File.expand_path('..')].first
    ios_build_dir = "#{root_dir}/ios/Build/Products"

    ENV['APP_NAME'] = 'Mattermost'
    ENV['REPLACE_ASSETS'] = 'true'
    ENV['BUILD_FOR_RELEASE'] = 'true'
    ENV['APP_SCHEME'] = 'mattermost'

    update_identifiers
    replace_assets

    sh "rm -rf #{ios_build_dir}/"
    sh "cd #{root_dir}/ios && xcodebuild -workspace Mattermost.xcworkspace -scheme Mattermost -configuration Release -parallelizeTargets CODE_SIGN_IDENTITY='' CODE_SIGNING_REQUIRED=NO SYMROOT='#{ios_build_dir}' #{more_xc_args} "
    sh "cd #{ios_build_dir}/#{rel_build_dir} && zip -r #{output_file} Mattermost.app"
    sh "mv #{ios_build_dir}/#{rel_build_dir}/#{output_file} #{root_dir}"
  end

end

platform :android do
  desc 'Build Android app'
  lane :build do
    unless configured
      configure
    end
    update_identifiers
    replace_assets
    pinned_certificates
    link_sentry({:os_type => "android"})
    build_android
    move_android_to_root
    upload_file_to_s3({:os_type => "android"})
  end

  desc 'Build an unsigned apk'
  lane :unsigned do
    UI.success('Building unsigned Android app')

    ENV['APP_NAME'] = 'Mattermost'
    ENV['REPLACE_ASSETS'] = 'true'
    ENV['BUILD_FOR_RELEASE'] = 'true'
    ENV['APP_SCHEME'] = 'mattermost'

    update_identifiers
    replace_assets

    gradle(
        task: 'assemble',
        build_type: 'Unsigned',
        project_dir: 'android/'
    )

    sh "mv #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]} #{Pathname.new(File.expand_path(File.dirname(__FILE__))).parent.to_s}/Mattermost-unsigned.apk"
  end

  lane :update_identifiers do
    # Set the name for the app
    app_name =  ENV['APP_NAME'] || 'Mattermost Beta'
    sh "echo '#{app_name}' > ../fastlane/metadata/android/en-US/title.txt"
    android_change_string_app_name(
        newName: app_name,
        stringsFile: './android/app/src/main/res/values/strings.xml'
    )

    package_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta'
    android_change_package_identifier(newIdentifier: package_id, manifest: './android/app/src/main/AndroidManifest.xml')
    android_update_application_id(app_folder_name: 'android/app', application_id: package_id)
    android_update_namespace(app_folder_name: 'android/app', namespace: package_id)

    app_scheme = ENV['APP_SCHEME'] || 'mattermost'
    find_replace_string(
      path_to_file: "./android/app/src/main/AndroidManifest.xml",
      old_string: 'scheme="mattermost"',
      new_string: "scheme=\'#{app_scheme}\'"
    )

    
    app_auth_scheme = get_auth_scheme

    find_replace_string(
        path_to_file: "./android/app/src/main/AndroidManifest.xml",
        old_string: 'scheme="mmauthbeta"',
        new_string: "scheme=\"#{app_auth_scheme}\"",
    )

    helpers_dir = './android/app/src/main/java/com/mattermost/helpers/'
    beta_dir = './android/app/src/main/java/com/mattermost/rnbeta/'
    release_dir = "./android/app/src/main/java/#{package_id.gsub '.', '/'}/"
    if release_dir != beta_dir
      unless Dir.exist?(".#{release_dir}")
        FileUtils.mkdir_p ".#{release_dir}"
      end

      sh "mv .#{beta_dir}* .#{release_dir}"

      Dir.glob(".#{release_dir}*.java") do |item|
        find_replace_string(
            path_to_file: item[1..-1],
            old_string: 'package com.mattermost.rnbeta;',
            new_string: "package #{package_id};"
        )
      end

      Dir.glob(".#{release_dir}*.kt") do |item|
        find_replace_string(
            path_to_file: item[1..-1],
            old_string: 'package com.mattermost.rnbeta',
            new_string: "package #{package_id}"
        )
      end

      Dir.glob('../android/app/src/main/java/com/mattermost/share/*.java') do |item|
        find_replace_string(
            path_to_file: item[1..-1],
            old_string: 'import com.mattermost.rnbeta.MainApplication;',
            new_string: "import #{package_id}.MainApplication;"
        )
      end

      Dir.glob('../android/app/src/main/java/com/mattermost/helpers/*.java') do |item|
        find_replace_string(
            path_to_file: item[1..-1],
            old_string: 'import com.mattermost.rnbeta.*;',
            new_string: "import #{package_id}.*;"
        )
      end

      Dir.glob('../android/app/src/main/java/com/mattermost/helpers/*.kt') do |item|
        find_replace_string(
            path_to_file: item[1..-1],
            old_string: 'import com.mattermost.rnbeta.*',
            new_string: "import #{package_id}.*"
        )
      end
    end
  end

  lane :replace_assets do
    if ENV['REPLACE_ASSETS'] == 'true'
      sh 'cp -R ../dist/assets/release/icons/android/* ../android/app/src/main/res/'
      sh 'cp -R ../dist/assets/release/splash_screen/android/* ../android/app/src/main/res/'
    end
    sh 'mkdir -p ../android/app/src/main/res/raw/'
    sh 'cp -R ../assets/sounds/* ../android/app/src/main/res/raw/'
  end

  lane :pinned_certificates do
    sh 'cp -R ../assets/certs/ ../android/app/src/main/assets/certs'
  end

  lane :deploy do |options|
    file_path = options[:file]

    unless file_path.nil?
      submit_to_google_play(file_path)
    end
  end

  error do |lane, exception|
    build_number = android_get_version_code(
        gradle_file: './android/app/build.gradle'
    )
    version_number = android_get_version_name(
        gradle_file: './android/app/build.gradle'
    )

   send_message_to_mattermost({
                                  :version_number => version_number,
                                  :build_number => build_number,
                                  :pretext => '',
                                  :title => 'Unsuccessful Build',
                                  :thumb_url => 'https://lh3.ggpht.com/XL0CrI8skkxnboGct-duyg-bZ_MxJDTrjczyjdU8OP2PM1dmj7SP4jL1K8JQeMIB3AM=w300',
                                  :msg =>  exception.message,
                                  :default_payloads => [:lane],
                                  :success => false,
                              })
  end

  def build_android
    config_mode = ENV['BUILD_FOR_RELEASE'] == 'true' ? 'Release' : 'Debug'
    build_task = ENV['ANDROID_BUILD_TASK'].nil? || ENV['ANDROID_BUILD_TASK'].empty? ? 'assemble' : ENV['ANDROID_BUILD_TASK']
    build_task = build_task.split(",")

    if build_task.include?("assemble")
      gradle(
          task: 'app:assemble',
          build_type: config_mode,
          project_dir: 'android/',
          properties: {
            'separateApk' => ENV["SEPARATE_APKS"] || false,
            'universalApk' => ENV["UNIVERSAL_APK"] || false,
          }
      )
    end

    if build_task.include?("bundle")
      gradle(
          task: 'app:bundle',
          build_type: config_mode,
          project_dir: 'android/',
      )
    end
  end

  def move_android_to_root
    app_name =  ENV['APP_NAME'] || 'Mattermost Beta'
    app_name_sub = app_name.gsub(" ", "_")
    build_task = ENV['ANDROID_BUILD_TASK'].nil? || ENV['ANDROID_BUILD_TASK'].empty? ? 'assemble' : ENV['ANDROID_BUILD_TASK']
    build_task = build_task.split(",")

    if build_task.include?("assemble")
      apks = lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS]
      json_path = lane_context[SharedValues::GRADLE_OUTPUT_JSON_OUTPUT_PATH]

      if json_path.nil? || json_path.empty?
        dir_name = File.dirname(apks.first)
        json_path = Dir.glob(File.join(dir_name, '*.json')).first
      end

      UI.message("JSON PATH APK #{json_path}")
      outputJson = load_config_json(json_path)
      paths = []
      apks.each do |apk|
        filename = File.basename(apk)
        output = outputJson["elements"].find { |o| o["outputFile"] == filename }
        unless output.nil?
          filterName = output["filters"].empty? ? '' : output["filters"].first["value"]
          name = "#{app_name_sub}"
          unless filterName.nil? || filterName.empty?
            name += "-#{filterName}"
          end
          new_apk_path = "#{Pathname.new(File.expand_path(File.dirname(__FILE__))).parent.to_s}/#{name}.apk"
          paths.push(new_apk_path)
          sh "mv #{apk} #{new_apk_path}"
          UI.message("APK PATH \"#{new_apk_path}\", #{filterName}")
        end
      end

      lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS] = paths
    end

    if build_task.include?("bundle")
      aab = lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH]
      new_aab_path = "#{Pathname.new(File.expand_path(File.dirname(__FILE__))).parent.to_s}/#{app_name_sub}.aab"
      sh "mv #{aab} #{new_aab_path}"
      UI.message("AAB PATH \"#{new_aab_path}\"")
    end
  end
end

def get_auth_scheme
  if ENV['BETA_BUILD'] == 'true'
    ENV['APP_AUTH_SCHEME_BETA'].to_s.empty? ? 'mmauthbeta' : ENV['APP_AUTH_SCHEME_BETA']
  else
    ENV['APP_AUTH_SCHEME'].to_s.empty? ? 'mmauth' : ENV['APP_AUTH_SCHEME']
  end
end

def load_config_json(json_path)
  config_file = File.read(json_path)
  JSON.parse(config_file)
end

def save_json_as_file(json_path, json)
  File.open(json_path, 'w') do |f|
    f.write(JSON.pretty_generate(json))
    f.write("\n")
  end
end

def send_message_to_mattermost(options)
  unless ENV['MATTERMOST_WEBHOOK_URL'].nil? || ENV['MATTERMOST_WEBHOOK_URL'].empty?
    mattermost(
        pretext: options[:pretext],
        message: options[:msg],
        default_payloads: options[:default_payloads],
        username: 'Fastlane',
        payload: {},
        attachment_properties: {
            title: options[:title],
            thumb_url: options[:thumb_url],
            fields: [{
                         title: 'Version',
                         value: options[:version_number],
                         short: true
                     },
                     {
                         title: 'Build Number',
                         value: options[:build_number],
                         short: true
                     }]
        },
        success: options[:success]
    )
  end
end

def get_apple_api_key
  api_key = ''
  unless ENV['IOS_API_KEY_ID'].nil? || ENV['IOS_API_KEY_ID'].empty? ||
    ENV['IOS_API_ISSUER_ID'].nil? || ENV['IOS_API_ISSUER_ID'].empty? ||
    ENV['IOS_API_KEY'].nil? || ENV['IOS_API_KEY'].empty?
      api_key_path = "#{ENV['IOS_API_KEY_ID']}.p8"
      File.open("../#{api_key_path}", 'w') do |f|
        key_string = ENV['IOS_API_KEY']
        p8_array = key_string.split('\n')
        p8_array.each_with_index do |value, index|
          f.write(value)
          f.write("\n") unless index == p8_array.length - 1
        end
      end

      api_key = app_store_connect_api_key(
        key_id: ENV['IOS_API_KEY_ID'],
        issuer_id: ENV['IOS_API_ISSUER_ID'],
        key_filepath: "./#{api_key_path}",
        in_house: ENV['IOS_IN_HOUSE'] == 'true', # optional but may be required if using match/sigh
      )

      File.delete("../#{api_key_path}")
    end

    return api_key
end

def submit_to_testflight(ipa_path)
  ipa = (Dir.glob(ipa_path).select { |f| File.file? f}).first

  if !ipa.nil?
    UI.success("ipa file #{ipa}")
    api_key = get_apple_api_key()
    unless api_key.empty?
      pilot(
        ipa: ipa,
        api_key: api_key
      )
    else
      UI.success("Uploading with Username / Password")
      pilot(
          ipa: ipa
      )
    end
  else
    UI.user_error! "ipa file does not exist #{ipa}"
    return
  end

  filename = File.basename(ipa)
  version_number = get_version_number(xcodeproj: './ios/Mattermost.xcodeproj', target: 'Mattermost')
  build_number = get_build_number(xcodeproj: './ios/Mattermost.xcodeproj')
  s3_folder = "#{ENV['AWS_FOLDER_NAME']}/#{version_number}/#{build_number}"
  public_link = "https://#{ENV['AWS_BUCKET_NAME']}/#{s3_folder}/#{filename}"


  # Send a build message to Mattermost
  pretext = '#### New iOS released ready to be published'
  msg = "Release has been cut and is on TestFlight ready to be published.\nDownload link: #{public_link}"

  if ENV['BETA_BUILD'] == 'true'
    pretext = '#### New iOS beta published to TestFlight'
    msg = "Sign up as a beta tester [here](https://testflight.apple.com/join/Q7Rx7K9P).\nDownload link: #{public_link}"
  end

  send_message_to_mattermost({
                                 :version_number => version_number,
                                 :build_number => build_number,
                                 :pretext => pretext,
                                 :title => '',
                                 :thumb_url => 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png',
                                 :msg => msg,
                                 :default_payloads => [],
                                 :success => true,
                             })
end

def submit_to_google_play(file_path)
  filenames = []
  if(file_path.include?("aab"))
    aab_filename = Dir.glob(file_path).select { |f| File.file? f}.first
    unless ENV['SUPPLY_JSON_KEY'].nil? || ENV['SUPPLY_JSON_KEY'].empty?
      supply(
          package_name: ENV['MAIN_APP_IDENTIFIER'] || ENV['SUPPLY_PACKAGE_NAME'],
          track: ENV['SUPPLY_TRACK'] || 'alpha',
          aab: aab_filename,
          skip_upload_apk: true
      )
    end
    filenames.push(aab_filename)
  else
    apks = Dir.glob(file_path).select { |f| File.file? f}
    filenames = apks.map {|f| File.basename(f)}

    if(apks.length > 0)
      unless ENV['SUPPLY_JSON_KEY'].nil? || ENV['SUPPLY_JSON_KEY'].empty?
        supply(
            package_name: ENV['MAIN_APP_IDENTIFIER'] || ENV['SUPPLY_PACKAGE_NAME'],
            track: ENV['SUPPLY_TRACK'] || 'alpha',
            apk_paths: apks,
            skip_upload_aab: true
        )
      end
    else
      UI.user_error! "There are no apks in #{apk_path}"
      return
    end
  end

  version_number = android_get_version_name(gradle_file: './android/app/build.gradle')
  build_number = android_get_version_code(gradle_file: './android/app/build.gradle')
  s3_folder = "#{ENV['AWS_FOLDER_NAME']}/#{version_number}/#{build_number}"
  public_path = "https://#{ENV['AWS_BUCKET_NAME']}/#{s3_folder}"
  links = (filenames.map { |f| "* #{public_path}/#{f}"}).join("\n")

  # Send a build message to Mattermost
  pretext = '#### New Android released ready to be published'
  msg = "Release has been cut and is on the Beta track ready to be published.\nDownload links:\n#{links}"

  if ENV['BETA_BUILD'] == 'true'
    pretext = '#### New Android beta published to Google Play'
    msg = "Sign up as a beta tester [here](https://play.google.com/apps/testing/com.mattermost.rnbeta).\nDownload links:\n#{links}"
  end

  send_message_to_mattermost({
                                 :version_number => version_number,
                                 :build_number => build_number,
                                 :pretext => pretext,
                                 :title => '',
                                 :thumb_url => 'https://lh3.ggpht.com/XL0CrI8skkxnboGct-duyg-bZ_MxJDTrjczyjdU8OP2PM1dmj7SP4jL1K8JQeMIB3AM=w300',
                                 :msg => msg,
                                 :default_payloads => [],
                                 :success => true,
                             })
end

def qa_build_message(options)
  abbreviated_commit_hash = last_git_commit[:abbreviated_commit_hash]
  os_type = options[:os_type]
  install_url = options[:install_url]

  unless ENV['MATTERMOST_WEBHOOK_URL'].nil? || ENV['MATTERMOST_WEBHOOK_URL'].empty?
    os_type = options[:os_type]

    if os_type == 'android'
      msg = "QA build [#{abbreviated_commit_hash}](https://github.com/mattermost/mattermost-mobile/commit/#{abbreviated_commit_hash}) — [Android APK Link](#{install_url})"
      mattermost(message: msg, username: 'Fastlane', icon_url: 'https://lh3.ggpht.com/XL0CrI8skkxnboGct-duyg-bZ_MxJDTrjczyjdU8OP2PM1dmj7SP4jL1K8JQeMIB3AM=w300')
    elsif os_type == 'ios'
      msg = "QA build [#{abbreviated_commit_hash}](https://github.com/mattermost/mattermost-mobile/commit/#{abbreviated_commit_hash}) — [iOS pList Link](#{install_url})"
      mattermost(message: msg, username: 'Fastlane', icon_url: 'https://support.apple.com/library/content/dam/edam/applecare/images/en_US/iOS/move-to-ios-icon.png')
    end
  else
    UI.success("PR Built for #{os_type}: #{install_url}")
  end
end
