// Copyright 2023 Mikhail Klementev. All rights reserved.
// Use of this source code is governed by a AGPLv3 license
// (or later) that can be found in the LICENSE file.

package kernel

import (
	"math/rand"
	"os"
	"os/signal"
	"path/filepath"
	"regexp"

	"github.com/rs/zerolog/log"

	"code.dumpstack.io/tools/out-of-tree/artifact"
	"code.dumpstack.io/tools/out-of-tree/cache"
	"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
	"code.dumpstack.io/tools/out-of-tree/fs"
)

func MatchPackages(km artifact.Target) (packages []string, err error) {
	pkgs, err := km.Distro.Packages()
	if err != nil {
		return
	}

	r, err := regexp.Compile(km.Kernel.Regex)
	if err != nil {
		return
	}

	exr, err := regexp.Compile(km.Kernel.ExcludeRegex)
	if err != nil {
		return
	}

	for _, pkg := range pkgs {
		if !r.MatchString(pkg) {
			continue
		}

		if km.Kernel.ExcludeRegex != "" && exr.MatchString(pkg) {
			continue
		}

		packages = append(packages, pkg)
	}

	return
}

func GenRootfsImage(imageFile string, download bool) (rootfs string, err error) {
	imagesPath := dotfiles.Dir("images")

	rootfs = filepath.Join(imagesPath, imageFile)
	if !fs.PathExists(rootfs) {
		if download {
			log.Info().Msgf("%v not available, start download", imageFile)
			err = cache.DownloadRootFS(imagesPath, imageFile)
		}
	}
	return
}

func ShuffleStrings(a []string) []string {
	// Fisher–Yates shuffle
	for i := len(a) - 1; i > 0; i-- {
		j := rand.Intn(i + 1)
		a[i], a[j] = a[j], a[i]
	}
	return a
}

func SetSigintHandler(variable *bool) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		counter := 0
		for range c {
			if counter == 0 {
				*variable = true
				log.Warn().Msg("shutdown requested, finishing work")
				log.Info().Msg("^C a couple of times more for an unsafe exit")
			} else if counter >= 3 {
				log.Fatal().Msg("unsafe exit")
			}

			counter += 1
		}
	}()

}