# 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
#

opt_out_usage

require "bundler/setup"
require "base64"
require_relative "helpers"

# load secrets before project configuration
Fastlane::Helpers.dev_load_dotenv_secrets
is_ci = Fastlane::Helpers.is_ci_environment?
local_development = !is_ci

# checks after calling Dotenv.load
attempt_force_upload_local_dev = ENV["FORCE_UPLOAD_LOCAL_DEV"] == "true"
android_has_permissions = false

if local_development
  # confirm that we want to force upload
  Fastlane::Helpers.confirm_force_upload if attempt_force_upload_local_dev
end

# Project configuration
PROJECT_NAME = ENV["IOS_PROJECT_NAME"]
PROJECT_SCHEME = ENV["IOS_PROJECT_SCHEME"]
SIGNING_CERTIFICATE = ENV["IOS_SIGNING_CERTIFICATE"]

# Environment setup
package_version = JSON.parse(File.read("../package.json"))["version"]
# most of these values are for local development
android_aab_path = "../android/app/build/outputs/bundle/release/app-release.aab"
android_gradle_file_path = "../android/app/build.gradle"
android_keystore_path = "../android/app/upload-keystore.jks"
android_play_store_json_key_path = "../android/app/play-store-key.json"
ios_connect_api_key_path = "../ios/certs/connect_api_key.p8"
ios_provisioning_profile_directory = "~/Library/MobileDevice/Provisioning\ Profiles"
ios_xcode_profile_path = "../ios/#{PROJECT_NAME}.xcodeproj"

default_platform(:ios)

platform :ios do
  desc "Sync ios version"
  lane :sync_version do
    increment_version_number(
      xcodeproj: "ios/#{PROJECT_NAME}.xcodeproj",
      version_number: package_version,
    )
  end

  desc "Push a new build to TestFlight Internal Testing"
  lane :internal_test do
    result = prepare_ios_build(prod_release: false)

    upload_to_testflight(
      api_key: result[:api_key],
      distribute_external: true,
      # TODO: fix error about the groups not being set correctly, fwiw groups are set in the app store connect
      groups: ENV["IOS_TESTFLIGHT_GROUPS"].split(","),
      changelog: "",
      skip_waiting_for_build_processing: false,
    ) if result[:should_upload]

    # Notify Slack about the new build
    if ENV["SLACK_CHANNEL_ID"]
      Fastlane::Helpers.upload_file_to_slack(
        file_path: result[:ipa_path],
        channel_id: ENV["SLACK_CHANNEL_ID"],
        initial_comment: "🍎 iOS v#{package_version} (Build #{result[:build_number]}) deployed to TestFlight",
        title: "#{PROJECT_NAME}-#{package_version}-#{result[:build_number]}.ipa",
      )
    else
      UI.important("Skipping Slack notification: SLACK_CHANNEL_ID not set.")
    end
  end

  desc "Prepare a new build for App Store submission"
  lane :deploy do
    result = prepare_ios_build(prod_release: true)

    upload_to_app_store(
      api_key: result[:api_key],
      skip_screenshots: true,
      skip_metadata: true,
      submit_for_review: false,
      automatic_release: false,
      skip_app_version_update: true,
    ) if result[:should_upload]

    # Notify Slack about the new build
    if ENV["SLACK_CHANNEL_ID"]
      Fastlane::Helpers.upload_file_to_slack(
        file_path: result[:ipa_path],
        channel_id: ENV["SLACK_CHANNEL_ID"],
        initial_comment: "🍎 iOS (Ready for Submission) v#{package_version} (Build #{result[:build_number]}) deployed to App Store Connect",
        title: "#{PROJECT_NAME}-#{package_version}-#{result[:build_number]}.ipa",
      )
    else
      UI.important("Skipping Slack notification: SLACK_CHANNEL_ID not set.")
    end
  end

  private_lane :prepare_ios_build do |options|
    if local_development
      # app breaks with Xcode 16.3
      xcode_select "/Applications/Xcode-16-2.app"

      # Set up API key, profile, and potentially certificate for local dev
      Fastlane::Helpers.ios_dev_setup_connect_api_key(ios_connect_api_key_path)
      Fastlane::Helpers.ios_dev_setup_provisioning_profile(ios_provisioning_profile_directory)
      Fastlane::Helpers.ios_dev_setup_certificate
    else
      # we need this for building ios apps in CI
      # else build will hang on "[CP] Embed Pods Frameworks"
      setup_ci(
        keychain_name: "build.keychain",
      )
    end

    required_env_vars = [
      "IOS_APP_IDENTIFIER",
      "IOS_CONNECT_API_KEY_BASE64",
      "IOS_CONNECT_API_KEY_PATH",
      "IOS_CONNECT_ISSUER_ID",
      "IOS_CONNECT_KEY_ID",
      "IOS_PROJECT_NAME",
      "IOS_PROJECT_SCHEME",
      "IOS_PROV_PROFILE_NAME",
      "IOS_PROV_PROFILE_PATH",
      "IOS_TEAM_ID",
      "IOS_TEAM_NAME",
    ]

    target_platform = options[:prod_release] ? "App Store" : "TestFlight"
    should_upload = Fastlane::Helpers.should_upload_app(target_platform)
    workspace_path = File.expand_path("../ios/#{PROJECT_NAME}.xcworkspace", Dir.pwd)
    ios_signing_certificate_name = "iPhone Distribution: #{ENV["IOS_TEAM_NAME"]} (#{ENV["IOS_TEAM_ID"]})"

    Fastlane::Helpers.verify_env_vars(required_env_vars)
    build_number = Fastlane::Helpers.ios_increment_build_number(ios_xcode_profile_path)
    Fastlane::Helpers.ios_verify_app_store_build_number(ios_xcode_profile_path)
    Fastlane::Helpers.ios_verify_provisioning_profile

    api_key = app_store_connect_api_key(
      key_id: ENV["IOS_CONNECT_KEY_ID"],
      issuer_id: ENV["IOS_CONNECT_ISSUER_ID"],
      key_filepath: ENV["IOS_CONNECT_API_KEY_PATH"],
      in_house: false,
    )

    # Update project to use manual code signing
    update_code_signing_settings(
      use_automatic_signing: false,
      path: "ios/#{PROJECT_NAME}.xcodeproj",
      team_id: ENV["IOS_TEAM_ID"],
      targets: [PROJECT_NAME],
      code_sign_identity: ios_signing_certificate_name,
      profile_name: ENV["IOS_PROV_PROFILE_NAME"],
      bundle_identifier: ENV["IOS_APP_IDENTIFIER"],
      build_configurations: ["Release"],
    )

    clear_derived_data

    # Print final build settings before archiving
    sh "xcodebuild -showBuildSettings -workspace #{workspace_path} " \
       "-scheme #{PROJECT_SCHEME} -configuration Release " \
       "| grep 'CODE_SIGN_STYLE\|PROVISIONING_PROFILE_SPECIFIER\|CODE_SIGN_IDENTITY\|DEVELOPMENT_TEAM' || true"

    cocoapods(
      podfile: "ios/Podfile",
      clean_install: true,
      deployment: true,
    )

    ipa_path = build_app({
      workspace: "#{workspace_path}",
      scheme: PROJECT_SCHEME,
      export_method: "app-store",
      output_directory: "build",
      clean: true,
      export_options: {
        method: "app-store",
        signingStyle: "manual",
        provisioningProfiles: {
          ENV["IOS_APP_IDENTIFIER"] => ENV["IOS_PROV_PROFILE_NAME"],
        },
        signingCertificate: ios_signing_certificate_name,
        teamID: ENV["IOS_TEAM_ID"],
      },
    })

    {
      api_key: api_key,
      build_number: build_number,
      ipa_path: ipa_path,
      should_upload: should_upload,
    }
  end
end

platform :android do
  desc "Sync android version"
  lane :sync_version do
    android_set_version_name(
      version_name: package_version,
      gradle_file: android_gradle_file_path.gsub("../", ""),
    )
  end

  desc "Push a new build to Google Play Internal Testing"
  lane :internal_test do
    upload_android_build(track: "internal")
  end

  desc "Push a new build to Google Play Store"
  lane :deploy do
    upload_android_build(track: "production")
  end

  private_lane :upload_android_build do |options|
    if local_development
      if ENV["ANDROID_KEYSTORE_PATH"].nil?
        ENV["ANDROID_KEYSTORE_PATH"] = Fastlane::Helpers.android_create_keystore(android_keystore_path)
      end

      if ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"].nil?
        ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"] = Fastlane::Helpers.android_create_play_store_key(android_play_store_json_key_path)
      end
    end

    required_env_vars = [
      "ANDROID_KEYSTORE",
      "ANDROID_KEYSTORE_PASSWORD",
      "ANDROID_KEYSTORE_PATH",
      "ANDROID_KEY_ALIAS",
      "ANDROID_KEY_PASSWORD",
      "ANDROID_PACKAGE_NAME",
      "ANDROID_PLAY_STORE_JSON_KEY_PATH",
    ]

    Fastlane::Helpers.verify_env_vars(required_env_vars)
    version_code = Fastlane::Helpers.android_increment_version_code(android_gradle_file_path)
    # TODO: uncomment when we have the permissions to run this action
    # Fastlane::Helpers.android_verify_version_code(android_gradle_file_path)

    target_platform = options[:track] == "production" ? "Google Play" : "Internal Testing"
    should_upload = Fastlane::Helpers.should_upload_app(target_platform)

    validate_play_store_json_key(
      json_key: ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"],
    )

    Fastlane::Helpers.with_retry(max_retries: 3, delay: 10) do
      gradle(
        task: "clean bundleRelease --stacktrace --info",
        project_dir: "android/",
        properties: {
          "android.injected.signing.store.file" => ENV["ANDROID_KEYSTORE_PATH"],
          "android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
          "android.injected.signing.key.alias" => ENV["ANDROID_KEY_ALIAS"],
          "android.injected.signing.key.password" => ENV["ANDROID_KEY_PASSWORD"],
        },
      )
    end

    upload_to_play_store(
      track: options[:track],
      json_key: ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"],
      package_name: ENV["ANDROID_PACKAGE_NAME"],
      skip_upload_changelogs: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
      track_promote_release_status: "completed",
      aab: android_aab_path,
    ) if should_upload && android_has_permissions

    # Notify Slack about the new build
    if ENV["SLACK_CHANNEL_ID"]
      Fastlane::Helpers.upload_file_to_slack(
        file_path: android_aab_path,
        channel_id: ENV["SLACK_CHANNEL_ID"],
        initial_comment: "🤖 Android v#{package_version} (Build #{version_code}) deployed to #{target_platform}",
        title: "#{PROJECT_NAME}-#{package_version}-#{version_code}.aab",
      )
    else
      UI.important("Skipping Slack notification: SLACK_CHANNEL_ID not set.")
    end
  end
end
