#!/usr/bin/env ruby
# frozen_string_literal: true

#  Copyright (c) 2020-2024, Puzzle ITC. This file is part of
#  hitobito and licensed under the Affero General Public License version 3
#  or later. See the COPYING file at the top-level directory or at
#  https://github.com/hitobito/hitobito.

require "fileutils"
require "pathname"

# Allows switching wagons quickly (depends on https://direnv.net/)
class Setup
  USED_RUBY_VERSION = "3.2.6"
  USED_NODE_VERSION = "16.15.0"
  USED_YARN_VERSION = "1.22.19"

  YOUTH_DEPENDENT_WAGONS = %w[pbs cevi pro_natura jubla sjas jemk sac_cas dav].freeze

  def run
    write_and_copy(".tool-versions", <<~TOOL_VERSION)
      ruby #{USED_RUBY_VERSION}
      nodejs #{USED_NODE_VERSION}
      yarn #{USED_YARN_VERSION}
    TOOL_VERSION
    write_and_copy(".ruby-version", USED_RUBY_VERSION)

    write("Wagonfile", gemfile)
    write(".envrc", environment)
    handle_gemfile

    wagons.each do |wagon|
      FileUtils.mkdir("../hitobito_#{wagon}/tmp") unless Dir.exist?("../hitobito_#{wagon}/tmp")
      write("../hitobito_#{wagon}/.envrc", environment(wagon))
      FileUtils.touch("../hitobito_#{wagon}/config/environment.rb") # needed for rails-vim
      handle_gemfile(directory: "../hitobito_#{wagon}")
    end
  end

  def write(name, content)
    File.write(root.join(name), strip_heredoc(content))
  end

  def handle_gemfile(directory: Dir.pwd, gemfile_dev: ENV["BUNDLE_GEMFILE"])
    return unless gemfile_dev

    FileUtils.ln_s("#{directory}/Gemfile", "#{directory}/#{gemfile_dev}", force: true)

    if File.exist?("#{directory}/Gemfile.lock")
      FileUtils.cp("#{directory}/Gemfile.lock", "#{directory}/#{gemfile_dev}.lock")
    end
  end

  def write_and_copy(name, content)
    write(name, content)
    (wagons - core_aliases).each do |w|
      FileUtils.cp(root.join(name), root.join("../hitobito_#{w}"))
    end
  end

  def primary_wagon(name = ARGV.first)
    if !available.include?(name)
      puts "Specify one of the following: #{available.join("|")}"
      exit
    end
    name
  end

  def gemfile
    <<~GEMFILE
      # rubocop:disable Naming/FileName,Lint/MissingCopEnableDirective
      # frozen_string_literal: true

      # vim:ft=ruby

      ENV.fetch('WAGONS', '').split.each do |wagon|
        Dir[File.expand_path("../hitobito_\#{wagon}/hitobito_\#{wagon}.gemspec", __dir__)].each do |spec|
          gem File.basename(spec, '.gemspec'), path: File.expand_path('..', spec)
        end
      end
    GEMFILE
  end

  def environment(wagon = nil)
    <<~DIRENV
      #{"PATH_add ../hitobito/bin" if wagon}
      PATH_add bin
      export DISABLE_TEST_SCHEMA_MAINTENANCE=1
      export RAILS_DB_ADAPTER=postgresql
      export RAILS_DB_HOST=127.0.0.1
      export RAILS_DB_PORT=5432
      export RAILS_DB_USERNAME=hitobito
      export RAILS_DB_PASSWORD=hitobito
      export RAILS_DB_NAME=hit_#{primary_wagon || wagon}_dev
      export RAILS_TEST_DB_NAME=hit_#{wagon ? wagon : "core"}_test
      export RAILS_TMPDIR=#{root.join("../", wagon ? "hitobito_#{wagon}" : "", "tmp")}
      export SPRING_APPLICATION_ID=hit_#{wagon ? wagon : "core"}
      export PRIMARY_WAGON=#{primary_wagon}
      #{'export WAGONS="' + wagons.join(" ") + '"' if wagons.any?}
      log_status "hitobito now uses: #{wagons.any? ? wagons.join(", ") : "just the core"}"
      source_up
    DIRENV
  end

  def root
    @root ||= Pathname.new(File.expand_path("../../", __FILE__))
  end

  def wagons
    [primary_wagon] + dependencies.fetch(primary_wagon, []) - core_aliases
  end

  def dependencies
    YOUTH_DEPENDENT_WAGONS.product([%w[youth]]).to_h.merge({
      "tenants" => %w[generic],
      "bdp" => %w[pfadi_de],
    })
  end

  def available(excluded = %w[])
    @available ||= root.parent.entries
      .collect { |x| x.to_s[/hitobito_(.*)/, 1] }
      .compact.reject(&:empty?) - excluded + core_aliases
  end

  def core_aliases
    %w[core hitobito]
  end

  def strip_heredoc(string)
    val = string.scan(/^[ \t]*(?=\S)/).min
    indent = val ? val.size : 0
    string.gsub(/^[ \t]{#{indent}}/, "")
  end
end

Setup.new.run
