# 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 "xcodeproj"
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
android_has_permissions = false

# Project configuration
PROJECT_NAME = ENV["IOS_PROJECT_NAME"]
APP_NAME = ENV["IOS_PROJECT_NAME"] || begin
  app_json_path = File.expand_path("../app.json", __dir__)
  if File.exist?(app_json_path)
    app_config = JSON.parse(File.read(app_json_path))
    app_config["displayName"] if app_config.is_a?(Hash)
  end
rescue JSON::ParserError, Errno::ENOENT
  UI.important("Could not read app.json or invalid JSON format, using default app name")
  nil
end || "MobileApp"
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 (DEPRECATED)"
  lane :sync_version do
    UI.error("⛔ This lane is deprecated!")
    UI.error("Version management is now centralized in CI.")
    UI.error("Use: node scripts/version-manager.cjs apply <version> <ios> <android>")
    UI.user_error!("sync_version lane is deprecated - use version-manager.cjs instead")
  end

  desc "Push a new build to TestFlight Internal Testing"
  lane :internal_test do |options|
    test_mode = options[:test_mode] == true || options[:test_mode] == "true"

    result = prepare_ios_build(prod_release: false)

    if test_mode
      UI.important("🧪 TEST MODE: Skipping TestFlight upload")
      UI.success("✅ Build completed successfully!")
      UI.message("📦 IPA path: #{result[:ipa_path]}")
    else
      upload_to_testflight(
        api_key: result[:api_key],
        distribute_external: true,
        # Only external TestFlight groups are valid here
        groups: ENV["IOS_TESTFLIGHT_GROUPS"].split(","),
        changelog: "",
        skip_waiting_for_build_processing: false,
      ) if result[:should_upload]
    end

    # Update deployment timestamp in version.json
    if result[:should_upload]
      Fastlane::Helpers.update_deployment_timestamp("ios")
    end
  end

  desc "Deploy iOS app with automatic version management"
  lane :deploy_auto do |options|
    deployment_track = options[:deployment_track] || "internal"
    version_bump = options[:version_bump] || "build"
    test_mode = options[:test_mode] == true || options[:test_mode] == "true"

    UI.message("🚀 Starting iOS deployment")
    UI.message("  Track: #{deployment_track}")
    UI.message("  Version bump: #{version_bump}")
    UI.message("  Test mode: #{test_mode}")

    # In CI, version should already be set by version-manager.cjs
    # Verify it matches expected values
    if is_ci && version_bump == "skip"
      Fastlane::Helpers.verify_ci_version_match
    end

    # Prepare and build (no version bumping inside)
    result = prepare_ios_build(prod_release: deployment_track == "production", version_bump: version_bump)

    # Handle deployment based on track
    if test_mode
      UI.important("🧪 TEST MODE: Skipping App Store upload")
      UI.success("✅ Build completed successfully!")
    elsif deployment_track == "internal"
      upload_to_testflight(
        api_key: result[:api_key],
        distribute_external: false,
        skip_waiting_for_build_processing: false,
      ) if result[:should_upload]
    elsif deployment_track == "production"
      # For production, upload to TestFlight first, then promote
      upload_to_testflight(
        api_key: result[:api_key],
        distribute_external: false,
        skip_waiting_for_build_processing: true,
      ) if result[:should_upload]

      # TODO: Add app store submission when ready
      UI.important("⚠️  Production deployment uploaded to TestFlight. Manual App Store submission required.")
    end

    # Update deployment info
    if result[:should_upload] && !test_mode
      Fastlane::Helpers.update_deployment_timestamp("ios")
    end
  end

  private_lane :prepare_ios_build do |options|
    version_bump = options[:version_bump] || "build"

    if local_development
      # app breaks with Xcode 16.3
      xcode_select "/Applications/Xcode.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)

    if local_development && version_bump != "skip"
      Fastlane::Helpers.bump_local_build_number("ios")
    end

    # Read build number from version.json (already set by CI or local version-manager.cjs)
    build_number = Fastlane::Helpers.get_ios_build_number
    UI.message("📦 Using iOS build number: #{build_number}")

    # Update Xcode project with build number
    increment_build_number(
      build_number: build_number,
      xcodeproj: "ios/#{ENV["IOS_PROJECT_NAME"]}.xcodeproj",
    )

    # Verify build number is higher than TestFlight
    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,
      # setting to false for now because of NFCPassportReader locally we use ssh to install but the
      # workflow uses https so the Podfile.lock is different
      deployment: false,
    )

    ipa_path = build_app({
      workspace: "#{workspace_path}",
      scheme: PROJECT_SCHEME,
      export_method: "app-store",
      output_directory: "ios/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 (DEPRECATED)"
  lane :sync_version do
    UI.error("⛔ This lane is deprecated!")
    UI.error("Version management is now centralized in CI.")
    UI.error("Use: node scripts/version-manager.cjs apply <version> <ios> <android>")
    UI.user_error!("sync_version lane is deprecated - use version-manager.cjs instead")
  end

  desc "Push a new build to Google Play Internal Testing"
  lane :internal_test do |options|
    upload_android_build(track: "internal", test_mode: options[:test_mode])
  end

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

  desc "Build Android app without uploading"
  lane :build_only do |options|
    deployment_track = options[:deployment_track] || "internal"
    version_bump = options[:version_bump] || "build"

    UI.message("🔨 Building Android app (build only)")
    UI.message("  Track: #{deployment_track}")
    UI.message("  Version bump: #{version_bump}")

    upload_android_build(options.merge(skip_upload: true))
  end

  desc "Deploy Android app with automatic version management"
  lane :deploy_auto do |options|
    deployment_track = options[:deployment_track] || "internal"
    version_bump = options[:version_bump] || "build"
    test_mode = options[:test_mode] == true || options[:test_mode] == "true"

    UI.message("🚀 Starting Android deployment")
    UI.message("  Track: #{deployment_track}")
    UI.message("  Version bump: #{version_bump}")
    UI.message("  Test mode: #{test_mode}")

    # In CI, version should already be set by version-manager.cjs
    # Verify it matches expected values
    if is_ci && version_bump == "skip"
      Fastlane::Helpers.verify_ci_version_match
    end

    # Map deployment track to Play Store track
    play_store_track = deployment_track == "production" ? "production" : "internal"

    # Build and deploy
    upload_android_build(track: play_store_track, test_mode: test_mode, deployment_track: deployment_track, version_bump: version_bump)
  end

  private_lane :upload_android_build do |options|
    test_mode = options[:test_mode] == true || options[:test_mode] == "true"
    skip_upload = options[:skip_upload] == true || options[:skip_upload] == "true"
    version_bump = options[:version_bump] || "build"

    # Automatically skip uploads in local development (no local permissions for Play Store)
    # Uploads must be done by CI/CD machines with proper authentication
    if local_development && !skip_upload
      skip_upload = true
      UI.important("🏠 LOCAL DEVELOPMENT: Play Store uploads are disabled")
      UI.important("   Upload the AAB manually in the Play Console after the build finishes")
    end

    if local_development
      if ENV["ANDROID_KEYSTORE_PATH"].nil?
        ENV["ANDROID_KEYSTORE_PATH"] = Fastlane::Helpers.android_create_keystore(android_keystore_path)
      end
    end

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

    Fastlane::Helpers.verify_env_vars(required_env_vars)

    if local_development && version_bump != "skip"
      Fastlane::Helpers.bump_local_build_number("android")
    end

    # Read version code from version.json (already set by CI or local version-manager.cjs)
    version_code = Fastlane::Helpers.get_android_build_number
    UI.message("📦 Using Android build number: #{version_code}")

    # Update build.gradle with version code
    increment_version_code(
      version_code: version_code,
      gradle_file_path: android_gradle_file_path.gsub("../", ""),
    )

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

    Fastlane::Helpers.with_retry(max_retries: 3, delay: 10) do
      gradle(
        task: "clean bundleRelease --stacktrace --info",
        project_dir: "android/",
        properties: {
          "MYAPP_UPLOAD_STORE_FILE" => ENV["ANDROID_KEYSTORE_PATH"],
          "MYAPP_UPLOAD_STORE_PASSWORD" => ENV["ANDROID_KEYSTORE_PASSWORD"],
          "MYAPP_UPLOAD_KEY_ALIAS" => ENV["ANDROID_KEY_ALIAS"],
          "MYAPP_UPLOAD_KEY_PASSWORD" => ENV["ANDROID_KEY_PASSWORD"] == "EMPTY" ? "" : ENV["ANDROID_KEY_PASSWORD"],
        },
      )
    end

    if test_mode || skip_upload
      if skip_upload
        UI.important("🔨 BUILD ONLY: Skipping Play Store upload")
        if local_development
          UI.important("📦 Manual upload required: #{android_aab_path}")
        end
      else
        UI.important("🧪 TEST MODE: Skipping Play Store upload")
      end
      UI.success("✅ Build completed successfully!")
      UI.message("📦 AAB path: #{android_aab_path}")
    else
      if should_upload
        begin
          upload_options = {
            track: options[:track],
            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,
          }
          # In local development, use the JSON key file; in CI rely on ADC
          if local_development
            upload_options[:json_key] = ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"]
          else
            # In CI, try to use ADC credentials file directly
            adc_creds_path = ENV["GOOGLE_APPLICATION_CREDENTIALS"]
            if adc_creds_path && File.exist?(adc_creds_path)
              UI.message("🔑 Using ADC credentials file: #{adc_creds_path}")
              begin
                # Try passing the credentials file content as json_key_data
                creds_content = File.read(adc_creds_path)
                upload_options[:json_key_data] = creds_content
              rescue => e
                UI.error("Failed to read ADC credentials: #{e.message}")
                # Fallback: let supply try to use ADC automatically
                UI.message("🔄 Falling back to automatic ADC detection")
              end
            else
              UI.error("❌ ADC credentials not found at: #{adc_creds_path}")
            end
          end

          upload_to_play_store(upload_options)
        rescue => e
          if e.message.include?("forbidden") || e.message.include?("403") || e.message.include?("insufficientPermissions")
            UI.error("❌ Play Store upload failed: Insufficient permissions")
            UI.error("Please fix permissions in Google Play Console")
            UI.important("Build saved at: #{android_aab_path}")
          else
            # Re-raise if it's a different error
            raise e
          end
        end
      else
        UI.message("Skipping Play Store upload (should_upload: false)")
      end
    end

    # Update deployment timestamp in version.json
    if should_upload
      Fastlane::Helpers.update_deployment_timestamp("android")
    end
  end
end
