import "../../fastlane/RootDirectoryFastfile"
import "../../fastlane/EnvFastfile"
import "../../fastlane/DotEnvFastfile"
import "../../fastlane/ConfigurationFastfile"
import "../../fastlane/BuildDirectoryFastfile"
import "../../fastlane/JsBundleFastfile"
import "../../fastlane/CodePushFastfile"
import "../../fastlane/PoEditorFastfile"
import "../../fastlane/SentryFastfile"
import "../../fastlane/ResizeImageFastfile"
import "../../fastlane/AwsFastfile"

PROGUARD_MAPPING_FILE = 'app/build/outputs/mapping/release/mapping.txt'
DEBUG_APK_FILE = 'app/build/outputs/apk/debug/app-debug.apk'
RELEASE_APK_FILE = 'app/build/outputs/apk/release/app-release.apk'
RELEASE_AAB_FILE = 'app/build/outputs/bundle/release/app-release.aab'
GOOGLE_SERVICES_JSON_FILE = 'app/google-services.json'

BUILD_TYPE_RELEASE = 'Release'

GOOGLE_PLAY_TRACK_INTERNAL = 'internal'

SPLASH_IMAGE_SIZES = {
  'mdpi' => 328,
  'hdpi' => 492,
  'xhdpi' => 656,
  'xxhdpi' => 984,
  'xxxhdpi' => 1312,
}
LAUNCHER_IMAGE_SIZES = {
  'ldpi' => 36,
  'mdpi' => 48,
  'hdpi' => 72,
  'xhdpi' => 96,
  'xxhdpi' => 144,
  'xxxhdpi' => 192,
}
NOTIFICATION_IMAGE_SIZES = {
  'ldpi' => 18,
  'mdpi' => 24,
  'hdpi' => 36,
  'xhdpi' => 48,
  'xxhdpi' => 72,
  'xxxhdpi' => 96,
}

default_platform(:android)

platform :android do

  before_all do
    init_root_project_directory_path(File.expand_path('../..'))
    init_environment_variables()
    ensure_configuration()
  end

  desc "Create APK"
  lane :build_app do
    clean_build_directory()

    create_native_resources

    clean_android

    set_android_version_code
    set_android_version_name

    prepare_source_code_for_js_bundle()

    create_release_binaries
    #FIXME: investigate. APK cant be unzipped on Jenkins after migration to RN 0.66.4
    #test_binary_file
  end

  desc "Create launcher icon"
  lane :create_launcher_icon do
    create_images(
      launcher_icon(),
      './android/app/src/main/res/mipmap',
      'ic_launcher.png',
      LAUNCHER_IMAGE_SIZES
    )
    create_images(
      launcher_adaptive_icon(),
      './android/app/src/main/res/drawable',
      'ic_launcher_foreground.png',
      LAUNCHER_IMAGE_SIZES
    )
    create_images(
      launcher_monochrome_icon(),
      './android/app/src/main/res/drawable',
      'ic_launcher_monochrome.png',
      LAUNCHER_IMAGE_SIZES
    )
  end

  desc "Create splash screen image"
  lane :create_splash_screen_image do
    create_images(
      splash_image(),
      './android/app/src/main/res/drawable',
      'ic_splash.png',
      SPLASH_IMAGE_SIZES
    )
  end

  desc "Create notification icon"
  lane :create_notification_icon do
    create_images(
      notification_icon(),
      './android/app/src/main/res/drawable',
      'notification_icon.png',
      NOTIFICATION_IMAGE_SIZES
    )
  end

  def create_images(
    relative_image_path_to_read,
    relative_directory_path_to_write,
    image_name_to_write,
    image_sizes)
    absolute_image_path_to_read = "#{root_project_directory_path()}/#{relative_image_path_to_read}"
    image_sizes.each do |screen_dimention, image_size|
      absolute_image_directory_path_to_write = "#{root_project_directory_path()}/#{relative_directory_path_to_write}-#{screen_dimention}"
      absolute_image_path_to_write = "#{absolute_image_directory_path_to_write}/#{image_name_to_write}"
      FileUtils.mkdir_p(absolute_image_directory_path_to_write)
      File.open(absolute_image_path_to_write, 'w').close
      resize_image(
        absolute_image_path_to_read,
        image_size,
        image_size,
        absolute_image_path_to_write
      )
    end
  end

  desc "Create release binaries"
  lane :create_release_binaries do
    gradle(
      task: gradle_task(),
      build_type: BUILD_TYPE_RELEASE,
      flags: "--no-daemon --stacktrace --info",
      properties: {
        'android.injected.signing.store.file' => google_play_keystore_file_path(),
        'android.injected.signing.store.password' => google_play_keystore_file_password(),
        'android.injected.signing.key.alias' => google_play_keystore_key_alias(),
        'android.injected.signing.key.password' => google_play_keystore_key_password(),
      }
    )
  end

  desc "Set Android version code"
  lane :set_android_version_code do
    android_set_version_code(version_code: version_code())
  end

  desc "Set Android version name"
  lane :set_android_version_name do
    android_set_version_name(version_name: application_version())
  end

  desc "Upload binaries"
  lane :upload_binaries do
    store = store()
    if store == STORE_STORE
      upload_binaries_to_play_store
    elsif store === STORE_S3
      upload_binaries_to_aws_s3
    else
      raise "no upload_binaries_to_* to store #{store}"
    end
  end

  desc "Upload binaries to PlayStore"
  lane :upload_binaries_to_play_store do
    if android_use_apk()
      upload_apk_to_play_store
    else
      upload_aab_to_play_store
    end
  end

  desc "Upload apk to PlayStore"
  lane :upload_apk_to_play_store do
    upload_to_play_store(
      json_key: google_play_json_file_path(),
      track: google_play_track(),
      apk: "#{root_project_directory_path()}/android/#{release_binary_file()}",
      package_name: android_application_id(),
      version_name: application_version(),
      version_code: version_code(),
      skip_upload_metadata: true,
      skip_upload_aab: true,
      skip_upload_apk: false,
      skip_upload_changelogs: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
      mapping: "#{root_project_directory_path()}/android/#{PROGUARD_MAPPING_FILE}"
    )
  end

  desc "Upload aab to PlayStore"
  lane :upload_aab_to_play_store do
    upload_to_play_store(
      json_key: google_play_json_file_path(),
      track: google_play_track(),
      aab: "#{root_project_directory_path()}/android/#{release_binary_file()}",
      package_name: android_application_id(),
      version_name: application_version(),
      version_code: version_code(),
      skip_upload_metadata: true,
      skip_upload_aab: false,
      skip_upload_apk: true,
      skip_upload_changelogs: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
      mapping: "#{root_project_directory_path()}/android/#{PROGUARD_MAPPING_FILE}"
    )
  end

  desc "Upload binaries to AWS S3"
  lane :upload_binaries_to_aws_s3 do
    apk_file = "#{root_project_directory_path()}/android/#{release_binary_file()}"
    aws_file_name = "android_#{brand()}_#{environment()}.#{binary_file_extension()}"
    prefix = aws_binaries_name_prefix()
    if !prefix.nil? && !prefix.empty?
      aws_file_name = "#{prefix}_#{aws_file_name}"
    end
    aws_s3_upload(
      aws_access_key(),
      aws_secret_access_key(),
      aws_region(),
      aws_bucket(),
      aws_file_name,
      apk_file
    )
  end

  def google_play_track()
    return GOOGLE_PLAY_TRACK_INTERNAL
  end

  desc "Clean Android build folder"
  lane :clean_android do
    gradle(task: "clean")
  end

  desc "Install release apk on device"
  lane :install_release_apk_on_device do
    Dir.chdir("..") do
      sh('adb', 'install', RELEASE_APK_FILE)
    end
  end

  desc "Install debug apk on device"
  lane :install_debug_apk_on_device do
    Dir.chdir("..") do
      sh('adb', 'install', DEBUG_APK_FILE)
    end
  end

  desc "Copy google-services.json file"
  lane :copy_google_services_json_file do
    source_file = "#{root_project_directory_path()}/#{android_google_services_json_file()}"
    destination_file = "#{root_project_directory_path()}/android/#{GOOGLE_SERVICES_JSON_FILE}"
    FileUtils.cp(source_file, destination_file)
  end

  def version_code()
    if store() == STORE_STORE
      return get_latest_version_code_from_google_play() + 1
    else
      return 1
    end
  end

  def get_latest_version_code_from_google_play()
    version_codes = google_play_track_version_codes(
      package_name: android_application_id(),
      track: google_play_track(),
      json_key: google_play_json_file_path(),
    )
    if version_codes.empty?
      return 0
    end
    return version_codes.max()
  end

  desc "Test binary file"
  lane :test_binary_file do
    original_apk = "#{root_project_directory_path()}/android/#{RELEASE_APK_FILE}"
    unzipped_apk = "#{root_project_directory_path()}/#{ANDROID_TEST_DIRECTORY}/unzippedApk"
    FileUtils.mkdir_p(unzipped_apk)
    sh "unzip #{original_apk} -d #{unzipped_apk}"
    bundle_relative_path = "#{ANDROID_TEST_DIRECTORY}/unzippedApk/assets/#{ANDROID_BUNDLE_NAME}"
    # TODO: upgrade. uncomment
    # test_js_bundle(bundle_relative_path)
    test_apk_signature_scheme(original_apk)
  end

  def test_apk_signature_scheme(apk_path)
    apk_signing_info = sh "#{apksigner_path()} verify --verbose #{apk_path}"
    has_v1_scheme = apk_signing_info.include?("Verified using v1 scheme (JAR signing): true")
    has_v2_scheme = apk_signing_info.include?("Verified using v2 scheme (APK Signature Scheme v2): true")
    if !has_v1_scheme
      raise "APK is not signed with v1 scheme"
    elsif !has_v2_scheme
      raise "APK is not signed with v2 scheme"
    end
  end

  def apksigner_path()
    android_home_dir = ENV['ANDROID_HOME'] || ENV['ANDROID_SDK_ROOT'] || ENV['ANDROID_SDK']
    build_tools_dir = "#{android_home_dir}/build-tools"
    max_build_tools_dir_name = Dir.entries(build_tools_dir).last
    max_build_tools_dir = "#{build_tools_dir}/#{max_build_tools_dir_name}"
    apksigner = "#{max_build_tools_dir}/apksigner"
    return apksigner
  end

  desc "Creates build.properties file"
  lane :create_build_properties_file do
    build_properties_directory_path = "#{root_project_directory_path()}/android/app/generated"
    build_properties_file_path = "#{build_properties_directory_path}/build.properties"
    build_properties_file_content = build_properties_file_content_array().join("\n")

    FileUtils.mkdir_p(build_properties_directory_path)
    File.open(build_properties_file_path, 'w') { |file| file.write(build_properties_file_content) }
  end

  def build_properties_file_content_array()
    return [
      "applicationId=#{android_application_id()}",
      "appName=#{application_name()}",
      "brand=#{brand()}",
      "environment=#{environment()}",
      "splashBackgroundColor=#{splash_background_color()}",
      "launcherBackgroundGradientStartColor=#{launcher_adaptive_icon_background_gradient_start_color()}",
      "launcherBackgroundGradientEndColor=#{launcher_adaptive_icon_background_gradient_end_color()}",
      "launcherBackgroundGradientAngle=#{launcher_adaptive_icon_background_gradient_angle()}",
      "notificationIconColor=#{notification_icon_color()}",
      "statusBarColor=#{status_bar_color()}",
      "loginRedirectionScheme=#{redirection_scheme()}",
      "loginRedirectionHost=#{redirection_host()}",
      "loginRedirectionPort=#{redirection_port()}",
      "deepLinkFirebaseHost=#{deep_link_firebase_host()}",
      "deepLinkInsightsHost=#{deep_link_insights_host()}",
      "auth0SdkCallbackScheme=#{android_auth0_sdk_callback_scheme()}",
      "auth0SdkCallbackHost=#{android_auth0_sdk_callback_host()}",
      "auth0SdkCallbackPath=#{android_auth0_sdk_callback_path()}",
      "codePushServerUrl=#{code_push_server_url()}",
    ]
  end

  desc "Creates native resource (images, icons, configs etc)"
  lane :create_native_resources do
    create_launcher_icon
    create_splash_screen_image
    create_notification_icon
    copy_google_services_json_file
    create_build_properties_file
  end


  # --- Deploy binary ---

  desc "Deploy binary"
  lane :deploy_binary do
    build_app
    upload_binaries
    upload_proguard_mapping_to_sentry()
  end

  # ---

  def android_use_apk()
    android_binary_type() == ANDROID_BINARY_TYPE_APK
  end

  def release_binary_file()
    if android_use_apk()
      return RELEASE_APK_FILE
    else
      return RELEASE_AAB_FILE
    end
  end

  def binary_file_extension()
    if android_use_apk()
      return "apk"
    else
      return "aab"
    end
  end

  def gradle_task()
    if android_use_apk()
      return "app:assemble"
    else
      return "app:bundle"
    end
  end

end
