require "shellwords"
require "fileutils"

opt_out_usage
default_platform(:mac)

DESKTOP_DIR = File.expand_path("..", __dir__)
APP_IDENTIFIER = "com.nicotsx.zerobyte"

def env_value(*names)
	names.each do |name|
		value = ENV[name]
		return value unless value.nil? || value.empty?
	end

	nil
end

def latest_mas_pkg
	configured_pkg = env_value("ZEROBYTE_MAS_PKG")
	return File.expand_path(configured_pkg, DESKTOP_DIR) if configured_pkg

	packages = Dir[File.join(DESKTOP_DIR, "dist", "mas-arm64", "*.pkg")]
	UI.user_error!("No MAS package found. Run `bundle exec fastlane mac build_mas` first.") if packages.empty?

	packages.max_by { |path| File.mtime(path) }
end

def prepare_mas_output
	output_dir = File.join(DESKTOP_DIR, "dist", "mas-arm64")
	app_dir = File.join(output_dir, "Zerobyte.app")
	return unless File.exist?(app_dir)
	return if File.stat(app_dir).uid == Process.uid && File.writable?(app_dir)

	stale_output_dir = "#{output_dir}.stale.#{Time.now.strftime("%Y%m%d%H%M%S")}"
	FileUtils.mv(output_dir, stale_output_dir)
	FileUtils.mkdir_p(output_dir)
	UI.important("Moved stale MAS output to #{stale_output_dir}")
end

def app_store_api_key
	return @app_store_api_key if @app_store_api_key

	key_id = env_value("APP_STORE_CONNECT_API_KEY_ID", "ASC_KEY_ID")
	issuer_id = env_value("APP_STORE_CONNECT_ISSUER_ID", "ASC_ISSUER_ID")
	key_filepath = env_value("APP_STORE_CONNECT_API_KEY_PATH", "ASC_KEY_PATH")
	key_content = env_value("APP_STORE_CONNECT_API_KEY_CONTENT", "ASC_KEY_CONTENT")
	key_content_base64 = env_value("APP_STORE_CONNECT_API_KEY_BASE64", "ASC_KEY_BASE64")

	UI.user_error!("Set APP_STORE_CONNECT_API_KEY_ID or ASC_KEY_ID.") unless key_id
	UI.user_error!("Set APP_STORE_CONNECT_ISSUER_ID or ASC_ISSUER_ID.") unless issuer_id

	options = {
		key_id: key_id,
		issuer_id: issuer_id,
	}

	if key_filepath
		options[:key_filepath] = File.expand_path(key_filepath, DESKTOP_DIR)
	elsif key_content_base64
		options[:key_content] = key_content_base64
		options[:is_key_content_base64] = true
	elsif key_content
		options[:key_content] = key_content
	else
		UI.user_error!(
			"Set APP_STORE_CONNECT_API_KEY_PATH, APP_STORE_CONNECT_API_KEY_CONTENT, or APP_STORE_CONNECT_API_KEY_BASE64.",
		)
	end

	@app_store_api_key = app_store_connect_api_key(**options)
end

def mas_build_number
	explicit_build_number = env_value("ZEROBYTE_BUILD_NUMBER", "BUILD_NUMBER")
	return explicit_build_number if explicit_build_number

	run_number = env_value("GITHUB_RUN_NUMBER")
	run_attempt = env_value("GITHUB_RUN_ATTEMPT")
	return [run_number, run_attempt].compact.join(".") if run_number

	UI.user_error!("Set ZEROBYTE_BUILD_NUMBER, BUILD_NUMBER, or GITHUB_RUN_NUMBER.")
end

platform :mac do
	desc "Build the signed Mac App Store package"
	lane :build_mas do
		build_number = mas_build_number
		env = "ZEROBYTE_BUILD_NUMBER=#{Shellwords.escape(build_number)} "

		prepare_mas_output
		sh("cd #{Shellwords.escape(DESKTOP_DIR)} && #{env}bun run make:mas")
	end

	desc "Upload the latest signed Mac App Store package to App Store Connect"
	lane :upload_testflight do
		pkg = latest_mas_pkg
		UI.message("Uploading #{pkg}")

		upload_to_app_store(
			api_key: app_store_api_key,
			app_identifier: APP_IDENTIFIER,
			pkg: pkg,
			platform: "osx",
			skip_metadata: true,
			skip_screenshots: true,
			skip_app_version_update: true,
			force: true,
			run_precheck_before_submit: false,
		)
	end

	desc "Build and upload the Mac App Store package to App Store Connect"
	lane :beta do |options|
		build_mas unless options[:skip_build] || ENV["ZEROBYTE_SKIP_MAS_BUILD"] == "true"
		upload_testflight
	end
end
