package main

import (
	"os"
	"os/exec"
	"syscall"

	"github.com/rs/zerolog/log"
	"gopkg.in/yaml.v3"

	config "novit.tech/direktil/pkg/bootstrapconfig"
)

func bootV2() {
	log.Info().Msg("-- boot v2 --")

	kernelVersion := unameRelease()
	log.Info().Str("version", kernelVersion).Msg("Linux")

	cfg := &config.Config{}

	{
		f, err := os.Open("/config.yaml")
		if err != nil {
			fatal("failed to open /config.yaml: ", err)
		}

		err = yaml.NewDecoder(f).Decode(cfg)
		f.Close()

		if err != nil {
			fatal("failed to parse /config.yaml: ", err)
		}
	}

	log.Info().Msg("config loaded")

	if cfg.AntiPhishingCode != "" {
		log.Info().Str("anti-phishing-code", cfg.AntiPhishingCode).Send()
	}

	auths = cfg.Auths

	// mount kernel modules
	if cfg.Modules == "" {
		log.Warn().Msg("NOT mounting modules (\"modules:\" not specified)")
	} else {
		log.Info().Str("from", cfg.Modules).Msg("mounting modules")
		mountSquahfs(cfg.Modules, "/modules")

		modulesSourcePath := "/modules/lib/modules/" + kernelVersion
		if _, err := os.Stat(modulesSourcePath); err != nil {
			fatal("invalid modules dir: ", err)
		}

		os.MkdirAll("/lib/modules", 0755)
		if err := os.Symlink(modulesSourcePath, "/lib/modules/"+kernelVersion); err != nil {
			fatal("failed to symlink modules: ", err)
		}
	}

	// load basic modules
	for _, module := range []string{"unix"} {
		log.Info().Str("module", module).Msg("loading module")
		run("modprobe", module)
	}

	// devices init
	log.Info().Msg("starting udevd")
	err := exec.Command("udevd").Start()
	if err != nil {
		fatal("failed to start udevd: ", err)
	}

	log.Info().Msg("udevadm triggers")
	run("udevadm", "trigger", "-c", "add", "-t", "devices")
	run("udevadm", "trigger", "-c", "add", "-t", "subsystems")

	log.Info().Msg("udevadm settle")
	run("udevadm", "settle")

	// networks
	setupNetworks(cfg)

	// Wireguard VPN
	// TODO startVPN()

	// SSH service
	startSSH(cfg)

	// dmcrypt blockdevs
	setupCrypt(cfg.PreLVMCrypt, map[string]string{})

	// LVM
	setupLVM(cfg)

	// bootstrap the system
	bootstrap(cfg)

	// finalize
	finalizeBoot()
}

func finalizeBoot() {
	// switch root
	log.Info().Msg("switching root")
	err := syscall.Exec("/sbin/switch_root", []string{"switch_root",
		"-c", "/dev/console", "/system", "/sbin/init"}, os.Environ())
	fatal("switch_root failed: ", err)
}
