//go:build testtool

package main

import (
	"encoding/gob"
	"log"
	"net"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"slices"
	"strconv"
	"strings"

	"hakurei.app/fhs"
	"hakurei.app/vfs"

	"hakurei.app/internal/pkg/internal/testtool/expected"
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("testtool: ")

	if os.Getenv("HAKUREI_BINFMT") == "1" {
		wantArgs := []string{"/interpreter", "/opt/bin/sample"}
		if !slices.Equal(os.Args, wantArgs) {
			log.Fatalf("Args: %q, want %q", os.Args, wantArgs)
		}

		if err := os.WriteFile("check", []byte("binfmt"), 0400); err != nil {
			log.Fatal(err)
		}

		return
	}

	environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
		for _, t := range []string{
			"CURE_JOBS=" + strconv.Itoa(runtime.NumCPU()),
			"CURE_LOAD=" + strconv.Itoa(runtime.NumCPU()+2),
		} {
			if s == t {
				return true
			}
		}
		return false
	})

	var hostNet, layers, promote bool
	if len(os.Args) == 2 && os.Args[0] == "testtool" {
		switch os.Args[1] {
		case "net":
			hostNet = true
			log.SetPrefix("testtool(net): ")
			break

		case "layers":
			layers = true
			log.SetPrefix("testtool(layers): ")
			break

		case "promote":
			promote = true
			log.SetPrefix("testtool(promote): ")

		default:
			log.Fatalf("Args: %q", os.Args)
			return
		}
	} else if wantArgs := []string{"testtool"}; !slices.Equal(os.Args, wantArgs) {
		log.Fatalf("Args: %q, want %q", os.Args, wantArgs)
	}

	var overlayRoot bool
	wantEnv := []string{"HAKUREI_TEST=1"}
	if len(environ) == 2 {
		overlayRoot = true
		if !layers && !promote {
			log.SetPrefix("testtool(overlay root): ")
		}
		wantEnv = []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"}
	}
	if !slices.Equal(wantEnv, environ) {
		log.Fatalf("Environ: %q, want %q", environ, wantEnv)
	}

	var overlayWork bool
	const (
		wantExec     = "/opt/bin/testtool"
		wantExecWork = "/work/bin/testtool"
	)
	var iftPath string
	if got, err := os.Executable(); err != nil {
		log.Fatalf("Executable: error = %v", err)
	} else {
		iftPath = filepath.Join(filepath.Dir(filepath.Dir(got)), "ift")

		if got != wantExec {
			switch got {
			case wantExecWork:
				overlayWork = true
				log.SetPrefix("testtool(overlay work): ")

			default:
				log.Fatalf("Executable: %q, want %q", got, wantExec)
			}
		}
	}

	wantHostname := "cure"
	if hostNet {
		wantHostname += "-net"
	}

	if hostname, err := os.Hostname(); err != nil {
		log.Fatalf("Hostname: error = %v", err)
	} else if hostname != wantHostname {
		log.Fatalf("Hostname: %q, want %q", hostname, wantHostname)
	}

	var m *vfs.MountInfo
	if f, err := os.Open(fhs.Proc + "self/mountinfo"); err != nil {
		log.Fatalf("Open: error = %v", err)
	} else {
		err = vfs.NewMountInfoDecoder(f).Decode(&m)
		closeErr := f.Close()
		if err != nil {
			log.Fatalf("Decode: error = %v", err)
		}
		if closeErr != nil {
			log.Fatalf("Close: error = %v", err)
		}
	}

	if ift, err := net.Interfaces(); err != nil {
		log.Fatal(err)
	} else if !hostNet {
		if len(ift) != 1 || ift[0].Name != "lo" {
			log.Fatalln("got interfaces", strings.Join(slices.Collect(func(yield func(ifn string) bool) {
				for _, ifi := range ift {
					if !yield(ifi.Name) {
						break
					}
				}
			}), ", "))
		}
	} else {
		var iftParent []net.Interface

		var r *os.File
		if r, err = os.Open(iftPath); err != nil {
			log.Fatal(err)
		} else {
			err = gob.NewDecoder(r).Decode(&iftParent)
			closeErr := r.Close()
			if err != nil {
				log.Fatal(err)
			}
			if closeErr != nil {
				log.Fatal(closeErr)
			}
		}

		if !reflect.DeepEqual(ift, iftParent) {
			log.Fatalf("Interfaces: %#v, want %#v", ift, iftParent)
		}
	}

	const checksumEmptyDir = "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"
	ident := expected.Offline
	log.Println(m)
	next := func() { m = m.Next; log.Println(m) }

	if overlayRoot {
		ident = expected.OvlRoot

		if m.Root != "/" || m.Target != "/" ||
			m.Source != "overlay" || m.FsType != "overlay" {
			log.Fatal("unexpected root mount entry")
		}
		var lowerdir []string
		for _, o := range strings.Split(m.FsOptstr, ",") {
			const lowerdirKey = "lowerdir+="
			if strings.HasPrefix(o, lowerdirKey) {
				lowerdir = append(lowerdir, o[len(lowerdirKey):])
			}
		}
		if !layers {
			if len(lowerdir) != 1 || filepath.Base(lowerdir[0]) != checksumEmptyDir {
				log.Fatal("unexpected artifact checksum")
			}
		} else {
			ident = expected.Layers

			if len(lowerdir) != 2 ||
				filepath.Base(lowerdir[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" ||
				filepath.Base(lowerdir[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" {
				log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdir, ", "))
			}
		}
	} else {
		if hostNet {
			ident = expected.Net
		}

		if m.Root != "/sysroot" || m.Target != "/" {
			log.Fatal("unexpected root mount entry")
		}

		next()
		if filepath.Base(m.Root) != "OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb" {
			log.Fatal("unexpected file artifact checksum")
		}

		next()
		if filepath.Base(m.Root) != checksumEmptyDir {
			log.Fatal("unexpected artifact checksum")
		}
	}

	if promote {
		ident = expected.Promote
	}

	next() // testtool artifact

	next()
	if overlayWork {
		ident = expected.Work
		if m.Root != "/" || m.Target != "/work" ||
			m.Source != "overlay" || m.FsType != "overlay" {
			log.Fatal("unexpected work mount entry")
		}
	} else {
		if filepath.Base(m.Root) != ident || m.Target != "/work" {
			log.Fatal("unexpected work mount entry")
		}
	}

	next()
	if filepath.Base(m.Root) != ident || m.Target != "/tmp" {
		log.Fatal("unexpected temp mount entry")
	}

	next()
	if m.Root != "/" || m.Target != "/proc" || m.Source != "proc" || m.FsType != "proc" {
		log.Fatal("unexpected proc mount entry")
	}

	next()
	if m.Root != "/" || m.Target != "/dev" || m.Source != "devtmpfs" || m.FsType != "tmpfs" {
		log.Fatal("unexpected dev mount entry")
	}

	for i := 0; i < 9; i++ { // private /dev entries
		next()
	}

	if m.Next != nil {
		log.Println("unexpected extra mount entries")
		for m.Next != nil {
			next()
		}
		os.Exit(1)
	}

	checkData := []byte{0}
	if hostNet {
		checkData = []byte("net")
	}
	if err := os.WriteFile("check", checkData, 0400); err != nil {
		log.Fatal(err)
	}
}
