package rosa

import (
	"slices"
	"strings"
)

var (
	_muon  = H("muon")
	_meson = H("meson")
)

// MesonHelper builds and tests a meson project.
type MesonHelper struct {
	// Use muon instead of meson.
	Muon bool

	// Runs after setup.
	ScriptCompileEarly string
	// Runs after compile.
	ScriptCompiled string
	// Runs after install.
	Script string

	// Flags passed to the setup command.
	Setup []KV
	// Test suites to skip.
	SkipTests []string
	// Whether to skip meson test.
	SkipTest bool
	// Run tests with interactive input/output.
	InteractiveTest bool
}

var _ Helper = new(MesonHelper)

// extra returns hardcoded meson runtime dependencies.
func (attr *MesonHelper) extra(int) P {
	if !attr.isPython() {
		return P{_muon}
	}
	return P{_meson}
}

// wantsChmod returns false.
func (*MesonHelper) wantsChmod() bool { return false }

// wantsWrite returns false.
func (*MesonHelper) wantsWrite() bool { return false }

// scriptEarly returns the zero value.
func (*MesonHelper) scriptEarly() string { return "" }

// wantsDir requests a new directory in TMPDIR.
func (*MesonHelper) wantsDir() (string, bool) { return `"$(mktemp -d)"`, false }

// isPython returns whether the legacy python implementation is used.
func (attr *MesonHelper) isPython() bool {
	return attr == nil ||
		!attr.Muon || len(attr.SkipTests) != 0 || attr.InteractiveTest
}

// script generates the cure script.
func (attr *MesonHelper) script(t Toolchain, name string) string {
	if attr == nil {
		attr = new(MesonHelper)
	}

	scriptCompiled := attr.ScriptCompiled
	if len(scriptCompiled) > 0 && scriptCompiled[0] != '\n' {
		scriptCompiled = "\n" + scriptCompiled
	}

	python := attr.isPython()
	muon := "muon"
	compile := " samu " + jobsFlagE
	destdir := "-d"
	if python {
		muon = "meson"
		compile = " compile " + jobsFlagE + " " + loadFlagE
		destdir = "--destdir"
	}

	var scriptTest string
	if !attr.SkipTest && t.opts&OptSkipCheck == 0 {
		scriptTest = `
` + muon + ` test \
	` + jobsFlagE + ` \
	-t 10`
		if python {
			scriptTest += ` \
	--print-errorlogs`
		} else {
			scriptTest += " -Rv"
		}
		if attr.InteractiveTest {
			scriptTest += ` \
	--interactive`
		}
		for _, suite := range attr.SkipTests {
			scriptTest += " \\\n\t--no-suite='" + suite + "'"
		}
	}

	return `
` + muon + ` setup \
	` + strings.Join(slices.Collect(func(yield func(string) bool) {
		for _, v := range append([]KV{
			{"wrap_mode", "nofallback"},
			{"prefix", "/system"},
			{"buildtype", "release"},
		}, attr.Setup...) {
			s := v[0]
			if v[1] != "" {
				s = "-D" + s + "=" + v[1]
			}
			if !yield(s) {
				return
			}
		}
	}), " \\\n\t") + ` \
	'/usr/src/` + name + `'
` + muon + compile + scriptCompiled + scriptTest + `
` + muon + ` install \
	` + destdir + ` /work
` + attr.Script
}
