Vagrant.require_version ">= 1.8.0"
Vagrant.configure("2") do |config|

  # config syntax:
  # {
  #  "defaults": {
  #     "box": "debian/bookworm64",
  #     "cpus": 1,
  #     "ip_start": "192.168.100.100",
  #     "memory": 2048,
  #     "name_prefix": "node-",
  #     "name_suffix": "",
  #     "port_start": 22000
  #   },
  #   "nodes": [
  #     {
  #       "box": "debian/bookworm64",
  #       "cpus": 1,
  #       "ip": "192.168.100.101",
  #       "memory": 2048,
  #       "name": "node-01",
  #       "port": 22001
  #     }
  #   ]
  # }

  VAGRANT__CONFIG_JSON = ENV["VAGRANT__CONFIG_JSON"] || "vagrant.json"

  if File.exist?(VAGRANT__CONFIG_JSON) then
    CONFIG = JSON.parse(File.read(VAGRANT__CONFIG_JSON))
  else
    CONFIG = {}
  end

  DEFAULTS = CONFIG["defaults"] || {}
  NODES = CONFIG["nodes"] || [{}]

  config.vm.provider "virtualbox" do |virtualbox|
    virtualbox.check_guest_additions = false
    virtualbox.gui = false
    virtualbox.linked_clone = true
  end

  NODES.to_enum.with_index(1).each do |entry, id|

    node_box    = entry["box"]    || DEFAULTS["box"] || "debian/bookworm64"
    node_cpus   = entry["cpus"]   || DEFAULTS["cpus"] || 1
    node_ip     = entry["ip"]     || "#{(DEFAULTS["ip_start"] || "192.168.100.100").split(".")[0...-1].join(".")}.#{(DEFAULTS["ip_start"] || "192.168.100.100").split(".")[-1].to_i+id}"
    node_memory = entry["memory"] || DEFAULTS["memory"] || 2048
    node_name   = entry["name"]   || "#{(DEFAULTS["name_prefix"] || "node-")}#{id.to_s.rjust(2, "0")}#{(DEFAULTS["name_suffix"] || "")}"
    node_port   = entry["port"]   || "#{(DEFAULTS["port_start"] || 22000)+id}"

    config.vm.define "#{node_name}" do |node|

      node.vm.box = node_box
      node.vm.hostname = node_name
      node.vm.network "forwarded_port", guest: "22", host: node_port, id: "ssh"
      node.vm.network "private_network", ip: node_ip

      node.vm.provider "virtualbox" do |node_virtualbox|
        node_virtualbox.cpus = node_cpus
        node_virtualbox.memory = node_memory
        node_virtualbox.name = node_name
      end

      node.trigger.before :destroy do |trigger|
        trigger.run = {inline: "bash -c 'ssh-add -d <(ssh-keygen -y -f .vagrant/machines/#{node_name}/virtualbox/private_key) || true'"}
      end

      if id == 1

        node.trigger.after :destroy do |trigger|
          trigger.run = {inline: "sh -c 'VBoxManage list vms | grep virtualbox | awk \"{print \\\$1}\" | xargs -rtn1 VBoxManage unregistervm --delete-all ; VBoxManage list hostonlynets | grep ^Name:  | grep vagrantnet | awk \"{print \\\$2}\" | xargs -rtn1 VBoxManage hostonlynet remove --name ; rm -f inventories/vagrant ; rm -rf .vagrant'"}
        end

      end

      if id == NODES.length

        node.trigger.before :provision do |trigger|
          trigger.run = {inline: "sh -c 'echo \"[{hosts: [all], tasks: [ansible.builtin.ping: ]}]\" > .vagrant/playbook_vagrant_dummy.yml'"}
        end

        node.vm.provision :ansible do |ansible|
          ansible.compatibility_mode = "2.0"
          ansible.limit = "all"
          ansible.playbook = ".vagrant/playbook_vagrant_dummy.yml"
          ansible.groups = {
            "all:vars" => {
              "ansible_ssh_common_args" =>  "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null",
              "ansible_become" => "true"
            }
          }
        end

        node.trigger.after :provision do |trigger|
          trigger.run = {inline: "sh -c 'rm -f .vagrant/playbook_vagrant_dummy.yml && mkdir -p inventories/ && ln -fs ../.vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory inventories/vagrant'"}
        end

      end

    end

  end

end
