package rosa

import (
	"slices"

	"hakurei.app/internal/pkg"
)

// newGoBootstrap returns the Go bootstrap toolchain.
func (t Toolchain) newGoBootstrap() pkg.Artifact {
	const checksum = "8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23"
	return t.New("go1.4-bootstrap", 0, t.AppendPresets(nil,
		Bash,
	), nil, []string{
		"CGO_ENABLED=0",
	}, `
mkdir -p /var/tmp/ /work/system/
cp -r /usr/src/go /work/system/
cd /work/system/go/src
chmod -R +w ..

./make.bash
`, pkg.Path(AbsUsrSrc.Append("go"), false, newTar(
		"https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz",
		checksum,
		pkg.TarGzip,
	)))
}

// newGo returns a specific version of the Go toolchain.
func (t Toolchain) newGo(
	version, checksum string,
	env []string,
	script string,
	extra ...pkg.Artifact,
) pkg.Artifact {
	name := "all"
	if presetOpts&OptSkipCheck != 0 {
		name = "make"
	}
	return t.New("go"+version, 0, t.AppendPresets(extra,
		Bash,
	), nil, slices.Concat([]string{
		"CC=cc",
		"GOCACHE=/tmp/gocache",
		"GOROOT_BOOTSTRAP=/system/go",
		"TMPDIR=/dev/shm/go",
	}, env), `
mkdir /work/system "${TMPDIR}"
cp -r /usr/src/go /work/system
cd /work/system/go/src
chmod -R +w ..
`+script+`
./`+name+`.bash

mkdir /work/system/bin
ln -s \
	../go/bin/go \
	../go/bin/gofmt \
	/work/system/bin
`, pkg.Path(AbsUsrSrc.Append("go"), false, newTar(
		"https://go.dev/dl/go"+version+".src.tar.gz",
		checksum,
		pkg.TarGzip,
	)))
}

func (t Toolchain) newGoLatest() (pkg.Artifact, string) {
	var (
		bootstrapEnv   []string
		bootstrapExtra []pkg.Artifact

		finalEnv []string
	)
	switch arch {
	case "amd64":
		bootstrapExtra = append(bootstrapExtra, t.newGoBootstrap())

	case "arm64", "riscv64":
		bootstrapEnv = append(bootstrapEnv, "GOROOT_BOOTSTRAP=/system")
		bootstrapExtra = t.AppendPresets(bootstrapExtra, gcc)
		finalEnv = append(finalEnv, "CGO_ENABLED=0")

	default:
		panic("unsupported target " + arch)
	}

	go119 := t.newGo(
		"1.19",
		"9_e0aFHsIkVxWVGsp9T2RvvjOc3p4n9o9S8tkNe9Cvgzk_zI2FhRQB7ioQkeAAro",
		append(bootstrapEnv, "CGO_ENABLED=0"), `
rm \
	crypto/tls/handshake_client_test.go \
	cmd/pprof/pprof_test.go \
	os/os_unix_test.go
sed -i \
	's/os\.Getenv("GCCGO")$/"nonexistent"/' \
	go/internal/gccgoimporter/importer_test.go
echo \
	'type syscallDescriptor = int' >> \
	os/rawconn_test.go
`, bootstrapExtra...)

	go121 := t.newGo(
		"1.21.13",
		"YtrDka402BOAEwywx03Vz4QlVwoBiguJHzG7PuythMCPHXS8CVMLvzmvgEbu4Tzu",
		[]string{"CGO_ENABLED=0"}, `
sed -i \
	's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
	cmd/link/internal/`+arch+`/obj.go

rm \
	crypto/tls/handshake_client_test.go \
	crypto/tls/handshake_server_test.go \
	os/os_unix_test.go
echo \
	'type syscallDescriptor = int' >> \
	os/rawconn_test.go
`, go119,
	)

	go123 := t.newGo(
		"1.23.12",
		"wcI32bl1tkqbgcelGtGWPI4RtlEddd-PTd76Eb-k7nXA5LbE9yTNdIL9QSOOxMOs",
		[]string{"CGO_ENABLED=0"}, `
sed -i \
	's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
	cmd/link/internal/`+arch+`/obj.go
`, go121,
	)

	go125 := t.newGo(
		"1.25.10",
		"TwKwatkpwal-j9U2sDSRPEdM3YesI4Gm88YgGV59wtU-L85K9gA7UPy9SCxn6PMb",
		[]string{"CGO_ENABLED=0"}, `
sed -i \
	's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
	cmd/link/internal/`+arch+`/obj.go

rm \
	os/root_unix_test.go \
	net/smtp/smtp_test.go
`, go123,
	)

	const (
		version  = "1.26.3"
		checksum = "lEiFocZFnN5fKvZzmwVdqc9pYUjAuhzqZGbuiOqxUP4XdcY8yECisKcqsQ_eNn1N"
	)
	return t.newGo(
		version,
		checksum,
		finalEnv, `
sed -i \
	's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
	cmd/link/internal/`+arch+`/obj.go
sed -i \
	's/cpu.X86.HasAVX512VBMI/& \&\& cpu.X86.HasPOPCNT/' \
	internal/runtime/gc/scan/scan_amd64.go

rm \
	os/root_unix_test.go \
	cmd/cgo/internal/testsanitizers/tsan_test.go \
	cmd/cgo/internal/testsanitizers/cshared_test.go
`, go125,
	), version
}
func init() {
	artifactsM[Go] = Metadata{
		f: Toolchain.newGoLatest,

		Name:        "go",
		Description: "the Go programming language toolchain",
		Website:     "https://go.dev/",

		ID: 1227,
	}
}
