package rosa

import (
	"errors"
	"io/fs"
	"os"
	"path/filepath"

	"hakurei.app/internal/pkg"
)

// gentooOverlay are symlinks on top of a Gentoo LLVM stage3 tarball for
// compatibility with the Rosa OS stage0 distribution.
type gentooOverlay struct{ stage3 pkg.Artifact }

// Kind returns the hardcoded [pkg.Kind] value.
func (a gentooOverlay) Kind() pkg.Kind { return kindGentooOverlay }

// Params is a noop.
func (a gentooOverlay) Params(*pkg.IContext) {}

// IsExclusive returns false: Cure performs a trivial filesystem write.
func (gentooOverlay) IsExclusive() bool { return false }

// Inputs returns the underlying Gentoo stage3.
func (a gentooOverlay) Inputs() []pkg.Artifact {
	return []pkg.Artifact{a.stage3}
}

func init() {
	pkg.Register(kindGentooOverlay, func(r *pkg.IRReader) pkg.Artifact {
		a := gentooOverlay{r.Next()}
		if _, ok := r.Finalise(); ok {
			panic(pkg.ErrUnexpectedChecksum)
		}
		return a
	})
}

// String returns a hardcoded name.
func (a gentooOverlay) String() string { return "gentoo-overlay" }

// Revision returns a hardcoded value incremented on layout changes.
func (a gentooOverlay) Revision() uint64 { return 0 }

// Cure installs the overlay.
func (a gentooOverlay) Cure(f *pkg.FContext) (err error) {
	pathname, _ := f.GetArtifact(a.stage3)
	var stage3 *os.Root
	if stage3, err = os.OpenRoot(pathname.String()); err != nil {
		return err
	}
	defer func() {
		closeErr := stage3.Close()
		if err == nil {
			err = closeErr
		}
	}()
	fsys := stage3.FS()

	system := f.GetWorkDir().Append("system")
	bin := system.Append("bin")
	if err = os.MkdirAll(bin.String(), 0700); err != nil {
		return
	}

	linknames := []string{
		"../../bin/sh",
	}

	var dents []os.DirEntry

	const llvm = "usr/lib/llvm"
	dents, err = fs.ReadDir(fsys, llvm)
	if err != nil {
		return
	}
	if len(dents) != 1 {
		return errors.New("stage3 /" + llvm + " contains more than one entry")
	}

	llvmBin := filepath.Join(llvm, dents[0].Name(), "bin")
	dents, err = fs.ReadDir(fsys, llvmBin)
	if err != nil {
		return
	}
	for _, dent := range dents {
		linknames = append(linknames, filepath.Join(
			"../..",
			llvmBin,
			dent.Name(),
		))
	}

	for _, linkname := range linknames {
		if err = os.Symlink(
			linkname,
			bin.Append(filepath.Base(linkname)).String(),
		); err != nil {
			return
		}
	}
	return
}
