# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# frozen_string_literal: true

require "bundler/gem_tasks"
require "rake/testtask"
require "rb_sys/extensiontask"
require "standard/rake"

GEMSPEC = Gem::Specification.load("opendal.gemspec")
CRATE_PACKAGE_NAME = "opendal-ruby"

desc "Copy core files for compilation"
task :copy_core do
  core_dir = "../../core"
  distributed_core_dir = "core"

  puts "Copying core files from #{core_dir} to #{distributed_core_dir}..."
  FileUtils.rm_rf(distributed_core_dir, secure: true)
  system("cp", "-Lr", core_dir, distributed_core_dir) # resolves symbolic links to a copy

  # Verify core files were copied
  core_files_count = `git -C #{File.expand_path(core_dir, __dir__)} ls-files -z`.split("\x0").length
  puts "Copied #{core_files_count} files from core directory"

  # Patch Cargo.toml for source distribution
  # When core files are copied locally, update Cargo.toml to reference the local copy
  if File.directory?(distributed_core_dir)
    cargo_toml = File.read("Cargo.toml")

    # Only patch if we haven't already and we're using the relative path
    if cargo_toml.include?('path = "../../core"')
      puts "Patching Cargo.toml to use local core directory..."
      cargo_toml.gsub!('path = "../../core"', 'path = "core"')
      File.write("Cargo.toml", cargo_toml)
    end
  end
end

RbSys::ExtensionTask.new(CRATE_PACKAGE_NAME, GEMSPEC) do |ext|
  ext.name = "opendal_ruby"
  ext.ext_dir = "."
  ext.lib_dir = "lib/opendal_ruby"

  ext.cross_compile = true
  ext.cross_platform = %w[
    x86_64-linux
    arm64-linux
    arm64-darwin
    arm64-darwin23
  ]

  # Override Ruby version requirement for native gems
  # This prevents automatic constraint to the build Ruby version (e.g., >= 3.3, < 3.4.dev)
  ext.cross_compiling do |gem_spec|
    # keep in sync with opendal.gemspec
    gem_spec.required_ruby_version = ">= 3.2", "< 3.5.dev"
  end
end

Rake::Task[:test].prerequisites << :compile

Rake::TestTask.new do |t|
  t.libs << "lib"
  t.libs << "test"
  t.pattern = "test/**/*_test.rb"
end

namespace :doc do
  task default: %i[rustdoc yard]

  desc "Generate YARD documentation"
  task :yard do
    run("bundle exec yard doc --plugin rustdoc -- lib tmp/doc/opendal_ruby.json")
  end

  desc "Generate Rust documentation as JSON"
  task :rustdoc do
    target_dir = "tmp"
    ext_dir = "opendal-ruby"
    run(<<~CMD)
      cargo +nightly-2025-10-12 rustdoc \
        --target-dir #{target_dir} \
        --package #{ext_dir} \
        -Zunstable-options \
        --output-format json \
        --lib \
        -- \
        --document-private-items
    CMD
  end

  def run(cmd)
    system(cmd)
    fail if $? != 0
  end
end

task doc: "doc:default"
task default: %i[compile test standard]
task purge: %i[clean clobber]

desc "report gem version"
task :version do
  print GEMSPEC.version
end

# Ensure core files are copied before compilation and packaging
Rake::Task["build"].enhance(["copy_core"]) if Rake::Task.task_defined?("build")

Rake::Task["release"].clear # clear the existing release task to allow override
Rake::Task["release:rubygem_push"].clear if Rake::Task.task_defined?("release:rubygem_push")

# overrides bundler's default rake release task
# we removed build and git tagging steps. Read more in ``./.github/workflows/release-ruby.yml`
# read more https://github.com/rubygems/rubygems/blob/master/bundler/lib/bundler/gem_helper.rb
desc "Multi-arch release"
task release: [
  "release:guard_clean",
  "release:rubygem_push"
]

namespace :release do
  desc "Push all gems to RubyGems"
  task :rubygem_push do
    # Push all gem files (source + platform-specific) like Nokogiri does
    # Bundler's built_gem_path only returns the last modified gem, so we glob all gems instead
    gem_files = Gem::Util.glob_files_in_dir("#{GEMSPEC.name}-*.gem", "pkg").sort

    if gem_files.empty?
      abort "No gem files found in pkg/"
    end

    puts "Found #{gem_files.length} gem(s) to push:"
    gem_files.each { |f| puts "  - #{File.basename(f)}" }

    gem_files.each do |gem_file|
      puts "\nPushing #{File.basename(gem_file)}..."
      sh "gem push #{gem_file}"
    end
  end
end
