package main

import (
	"context"
	"os"
	"path/filepath"
	"testing"

	"hakurei.app/check"
	"hakurei.app/container"
	"hakurei.app/internal/pkg"
	"hakurei.app/message"
)

// cache refers to an instance of [pkg.Cache] that might be open.
type cache struct {
	ctx context.Context
	msg message.Msg

	// Should generally not be used directly.
	c *pkg.Cache

	cures, jobs int
	// Primarily to work around missing landlock LSM.
	hostAbstract bool
	// Set SCHED_IDLE.
	idle bool
	// Unset [pkg.CSuppressInit].
	verboseInit bool
	// Loaded artifact of [rosa.QEMU].
	qemu pkg.Artifact

	base string
}

// open opens the underlying [pkg.Cache].
func (cache *cache) open() (err error) {
	if cache.c != nil {
		return os.ErrInvalid
	}

	var base *check.Absolute
	if cache.base, err = filepath.Abs(cache.base); err != nil {
		return
	} else if base, err = check.NewAbs(cache.base); err != nil {
		return
	}

	var flags int
	if cache.idle {
		flags |= pkg.CSchedIdle
	}
	if cache.hostAbstract {
		flags |= pkg.CHostAbstract
	}
	if !cache.verboseInit {
		flags |= pkg.CSuppressInit
	}

	done := make(chan struct{})
	defer close(done)
	go func() {
		select {
		case <-cache.ctx.Done():
			if testing.Testing() {
				return
			}
			os.Exit(2)

		case <-done:
			return
		}
	}()

	cache.msg.Verbosef("opening cache at %s", base)
	cache.c, err = pkg.Open(
		cache.ctx,
		cache.msg,
		flags,
		cache.cures,
		cache.jobs,
		base,
	)
	if err != nil {
		return
	}
	done <- struct{}{}

	if cache.qemu != nil {
		var pathname *check.Absolute
		pathname, _, err = cache.c.Cure(cache.qemu)
		if err != nil {
			cache.c.Close()
			return
		}

		pkg.RegisterArch("riscv64", container.BinfmtEntry{
			Offset: 0,
			Magic:  "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00",
			Mask:   "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff",
			Interpreter: pathname.Append(
				"system/bin",
				"qemu-riscv64",
			),
		})
		pkg.RegisterArch("arm64", container.BinfmtEntry{
			Offset: 0,
			Magic:  "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00",
			Mask:   "\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff",
			Interpreter: pathname.Append(
				"system/bin",
				"qemu-aarch64",
			),
		})
	}

	return
}

// Close closes the underlying [pkg.Cache] if it is open.
func (cache *cache) Close() {
	if cache.c != nil {
		cache.c.Close()
	}
}

// Do calls f on the underlying cache and returns its error value.
func (cache *cache) Do(f func(cache *pkg.Cache) error) error {
	if cache.c == nil {
		if err := cache.open(); err != nil {
			return err
		}
	}
	return f(cache.c)
}
