require "base64"
require "shellwords"
require "tempfile"

ENV["FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT"] ||= "60"

default_platform(:ios)

SCHEME = "Thingtime"
OUTPUT_DIRECTORY = "build"
OUTPUT_NAME = "Thingtime.ipa"

def api_key_xcargs
  @asc_p8 ||= begin
    f = Tempfile.new(["AuthKey_#{ENV.fetch('ASC_KEY_ID')}", ".p8"])
    f.binmode
    f.write(Base64.decode64(ENV.fetch("ASC_KEY_CONTENT")))
    f.flush
    f
  end

  args = [
    "-allowProvisioningUpdates",
    "-authenticationKeyID #{ENV.fetch('ASC_KEY_ID')}",
    "-authenticationKeyPath #{@asc_p8.path}"
  ]
  issuer_id = asc_issuer_id
  args << "-authenticationKeyIssuerID #{issuer_id}" if issuer_id
  args.join(" ")
end

def asc_issuer_id
  issuer_id = ENV["ASC_ISSUER_ID"].to_s.strip
  issuer_id.empty? ? nil : issuer_id
end

def thingtime_web_url_xcarg
  "THINGTIME_WEB_URL=#{Shellwords.escape(ENV.fetch('THINGTIME_WEB_URL', 'https://thingtime.com'))}"
end

def xcodebuild_xcargs
  args = []
  if ENV["PROVISIONING_PROFILE_SPECIFIER"].to_s.empty?
    args << api_key_xcargs
  else
    args << "CODE_SIGN_STYLE=Manual"
    args << "CODE_SIGN_IDENTITY=#{Shellwords.escape('Apple Distribution')}"
    args << "PROVISIONING_PROFILE_SPECIFIER=#{Shellwords.escape(ENV.fetch('PROVISIONING_PROFILE_SPECIFIER'))}"
  end
  args << "DEVELOPMENT_TEAM=#{ENV.fetch('DEVELOPMENT_TEAM')}"
  args << thingtime_web_url_xcarg
  args.join(" ")
end

def export_options
  options = {
    method: "app-store",
    signingStyle: "automatic",
    uploadSymbols: false
  }

  return options if ENV["PROVISIONING_PROFILE_SPECIFIER"].to_s.empty?

  options.merge(
    signingStyle: "manual",
    teamID: ENV.fetch("DEVELOPMENT_TEAM"),
    provisioningProfiles: {
      ENV.fetch("PRODUCT_BUNDLE_IDENTIFIER") => ENV.fetch("PROVISIONING_PROFILE_SPECIFIER")
    }
  )
end

def provisioning_profile_name
  ENV.fetch(
    "PROVISIONING_PROFILE_SPECIFIER",
    "Thingtime App Store #{ENV.fetch('PRODUCT_BUNDLE_IDENTIFIER')}"
  )
end

platform :ios do
  desc "Generate the Xcode project from project.yml"
  lane :generate do
    sh("which xcodegen > /dev/null || (echo 'Installing xcodegen...' && brew install xcodegen)")
    sh("cd .. && xcodegen generate")
  end

  desc "Build a signed Release archive (.ipa)"
  lane :build do
    generate
    setup_ci if ENV["CI"]
    unless ENV["SKIP_CERT_SYNC"] == "1"
      get_certificates(
        api_key: app_store_api_key,
        team_id: ENV.fetch("DEVELOPMENT_TEAM"),
        development: false,
        output_path: OUTPUT_DIRECTORY
      )
    end

    unless ENV["SKIP_PROFILE_SYNC"] == "1"
      ENV["PROVISIONING_PROFILE_SPECIFIER"] = provisioning_profile_name
      get_provisioning_profile(
        api_key: app_store_api_key,
        team_id: ENV.fetch("DEVELOPMENT_TEAM"),
        app_identifier: ENV.fetch("PRODUCT_BUNDLE_IDENTIFIER"),
        provisioning_name: provisioning_profile_name,
        cert_id: lane_context[SharedValues::CERT_CERTIFICATE_ID],
        force: true,
        output_path: OUTPUT_DIRECTORY
      )
    end

    build_app(
      scheme: SCHEME,
      configuration: "Release",
      output_directory: OUTPUT_DIRECTORY,
      output_name: OUTPUT_NAME,
      export_method: "app-store",
      include_symbols: false,
      xcargs: xcodebuild_xcargs,
      export_options: export_options
    )
  end

  desc "Build and upload to TestFlight"
  lane :beta do
    build
    upload_to_testflight(
      api_key: app_store_api_key,
      skip_waiting_for_build_processing: true,
      distribute_external: false
    )
  end

  desc "Upload an already-built IPA to TestFlight (IPA_PATH overrides the default build output)"
  lane :upload do
    upload_to_testflight(
      api_key: app_store_api_key,
      ipa: ENV["IPA_PATH"] || File.join(OUTPUT_DIRECTORY, OUTPUT_NAME),
      skip_waiting_for_build_processing: true,
      distribute_external: false
    )
  end

  private_lane :app_store_api_key do
    app_store_connect_api_key(
      key_id: ENV.fetch("ASC_KEY_ID"),
      issuer_id: asc_issuer_id,
      key_content: ENV.fetch("ASC_KEY_CONTENT"),
      is_key_content_base64: true,
      in_house: false
    )
  end
end
