# -*- ruby -*-
#
# 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.

require "pathname"

arrow_source = ENV["ARROW_SOURCE"]
if arrow_source.nil?
  raise "You must set ARROW_SOURCE environment variable"
end
ARROW_SOURCE = File.expand_path(arrow_source)
require "#{ARROW_SOURCE}/dev/tasks/linux-packages/package-task"
require "#{ARROW_SOURCE}/dev/release/binary-task"


module Helper
  private
  def top_source_dir
    Pathname(__dir__).parent.parent
  end

  def detect_version(release_time)
    version_env = ENV["VERSION"]
    return version_env if version_env

    versions_env = top_source_dir / "dev" / "release" / "versions.env"
    version = versions_env.read[/RELEASE="(.+?)"/, 1]
    version_native = detect_version_native
    if version_native.end_with?("-SNAPSHOT")
      formatted_release_time = release_time.strftime("%Y%m%d")
      version += "-dev#{formatted_release_time}"
    end
    version
  end

  def detect_version_native
    version_native_env = ENV["VERSION_NATIVE"]
    return version_native_env if version_native_env

    adbc_version_cmake = top_source_dir / "c" / "cmake_modules" / "AdbcVersion.cmake"
    adbc_version_cmake.read[/ADBC_VERSION "(.+?)"/, 1]
  end

  def detect_release_time
    release_time_env = ENV["RELEASE_TIME"]
    if release_time_env
      Time.parse(release_time_env).utc
    else
      Time.now.utc
    end
  end
end

class ADBCPackageTask < PackageTask
  include Helper

  def initialize
    release_time = detect_release_time
    super("apache-arrow-adbc", detect_version(release_time), release_time)
  end

  def define
    super
    define_rc_tasks
    define_release_tasks
  end

  private
  def define_archive_task
    file @archive_name do
      build_archive
    end

    if deb_archive_name != @archive_name
      file deb_archive_name => @archive_name do
        cp(@archive_name, deb_archive_name)
      end
    end

    if rpm_archive_name != @archive_name
      file rpm_archive_name => @archive_name do
        cp(@archive_name, rpm_archive_name)
      end
    end
  end

  def build_archive
    cd(top_source_dir) do
      sh("git",
         "archive",
         "HEAD",
         "--output", @full_archive_name,
         "--prefix", "#{@archive_base_name}/")
      rm_rf(@archive_base_name)
      sh("tar", "xf", @full_archive_name)
      mv(@archive_base_name, "#{@archive_base_name}.tmp")
      sh("cp", "-R", "-L", "#{@archive_base_name}.tmp", @archive_base_name)
      rm_rf("#{@archive_base_name}.tmp")
      sh("tar", "czf", @full_archive_name, @archive_base_name)
      rm_rf(@archive_base_name)
    end
  end

  def detect_go_version
    dot_env = File.join(__dir__, "..", "..", ".env")
    File.readlines(dot_env, chomp: true).grep(/\AGO=/)[0].split("=", 2)[1]
  end

  def docker_build_options(os, architecture)
    [
      "--build-arg", "GO_VERSION=#{detect_go_version}",
    ]
  end

  def apt_targets_default
    [
      "debian-bookworm",
      "debian-trixie",
      "ubuntu-jammy",
      "ubuntu-noble",
    ]
  end

  def yum_targets_default
    [
      "almalinux-8",
      "almalinux-9",
      "almalinux-10",
    ]
  end

  def yum_expand_variable(name)
    case name
    when "VERSION_NATIVE"
      detect_version_native
    else
      super
    end
  end

  def github_repository
    ENV["GITHUB_REPOSITORY"] || "apache/arrow-adbc"
  end

  def docker_image(os, architecture)
    "ghcr.io/#{github_repository}/package-#{super}"
  end

  def built_package_url(target_namespace, target)
    url = "https://github.com/#{github_repository}"
    url << "/releases/download/#{@version}/"
    case target_namespace
    when :apt
      if target.end_with?("-arm64")
        url << "#{target}.tar.gz"
      else
        url << "#{target}-amd64.tar.gz"
      end
    when :yum
      if target.end_with?("-aarch64")
        url << "#{target}.tar.gz"
      else
        url << "#{target}-x86_64.tar.gz"
      end
    end
    url
  end

  def package_dir_name
    "#{@package}-#{@version}"
  end

  def download_packages(target_namespace)
    download_dir = "#{ARROW_SOURCE}/packages/#{package_dir_name}"
    mkdir_p(download_dir)
    __send__("#{target_namespace}_targets").each do |target|
      url = built_package_url(target_namespace, target)
      archive = download(url, download_dir)
      cd(download_dir) do
        sh("tar", "xf", archive)
      end
    end
  end

  def upload_rc(target_namespace)
    targets = __send__("#{target_namespace}_targets")
    cd(apache_arrow_dir) do
      env = {
        "CROSSBOW_JOB_ID" => package_dir_name,
        "DEB_PACKAGE_NAME" => @package,
        "STAGING" => ENV["STAGING"] || "no",
        "UPLOAD_DEFAULT" => "0",
      }
      targets.each do |target|
        distribution = target.split("-")[0].upcase
        env["UPLOAD_#{distribution}"] = "1"
      end
      sh(env,
         "dev/release/05-binary-upload.sh",
         @version,
         "0")
    end
  end

  def define_rc_tasks
    [:apt, :yum].each do |target_namespace|
      tasks = []
      namespace target_namespace do
        desc "Upload RC #{target_namespace} packages"
        task :rc do
          download_packages(target_namespace)
          upload_rc(target_namespace)
        end
        tasks << "#{target_namespace}:release"
      end
      task target_namespace => tasks
    end
  end

  def release(target_namespace)
    targets = __send__("#{target_namespace}_targets")
    cd(apache_arrow_dir) do
      env = {
        "STAGING" => ENV["STAGING"] || "no",
        "DEPLOY_DEFAULT" => "0",
      }
      targets.each do |target|
        distribution = target.split("-")[0].upcase
        env["DEPLOY_#{distribution}"] = "1"
      end
      sh(env,
         "dev/release/post-02-binary.sh",
         @version,
         "0")
    end
  end

  def define_release_tasks
    [:apt, :yum].each do |target_namespace|
      tasks = []
      namespace target_namespace do
        desc "Release #{target_namespace} packages"
        task :release do
          release(target_namespace)
        end
        tasks << "#{target_namespace}:release"
      end
      task target_namespace => tasks
    end
  end
end

class ADBCLocalBinaryTask < LocalBinaryTask
  include Helper

  def initialize
    super([], top_source_dir.expand_path)
  end

  private
  def version
    @version ||= detect_version(detect_release_time)
  end
end

ADBCPackageTask.new.define
ADBCLocalBinaryTask.new.define
