package rosa

import (
	"errors"
	"io"
	"os"
	"sync"
	"syscall"

	"hakurei.app/fhs"
	"hakurei.app/internal/pkg"
)

// cureEtc contains deterministic elements of /etc, made available as part of
// [Toolchain]. This silences test suites expecting certain standard files to be
// available in /etc.
type cureEtc struct {
	// Whether to exclude ianaEtc.
	minimal bool
}

// NewEtc returns a [pkg.Artifact] containing deterministic elements of /etc.
func NewEtc(minimal bool) pkg.Artifact {
	return cureEtc{minimal}
}

// Cure writes hardcoded configuration to files under etc.
func (a cureEtc) Cure(t *pkg.FContext) (err error) {
	etc := t.GetWorkDir().Append("etc")
	if err = os.MkdirAll(etc.String(), 0700); err != nil {
		return
	}
	for _, f := range []KV{
		{"hosts", "127.0.0.1 localhost cure cure-net\n"},
		{"passwd", `root:x:0:0:System administrator:/proc/nonexistent:/bin/sh
cure:x:1023:1023:Cure:/usr/src:/bin/sh
nobody:x:65534:65534:Overflow user:/proc/nonexistent:/system/bin/false
`},
		{"group", `root:x:0:
cure:x:1023:
nobody:x:65534:
`},
	} {
		if err = os.WriteFile(
			etc.Append(f[0]).String(),
			[]byte(f[1]),
			0400,
		); err != nil {
			return
		}
	}

	if !a.minimal {
		iana, _ := t.GetArtifact(ianaEtc)

		buf := make([]byte, syscall.Getpagesize()<<3)
		for _, name := range []string{
			"protocols",
			"services",
		} {
			var dst, src *os.File
			if dst, err = os.OpenFile(
				etc.Append(name).String(),
				syscall.O_CREAT|syscall.O_EXCL|syscall.O_WRONLY,
				0400,
			); err != nil {
				return
			}

			if src, err = os.Open(
				iana.Append(name).String(),
			); err != nil {
				_ = dst.Close()
				return
			}

			_, err = io.CopyBuffer(dst, src, buf)
			closeErrs := [...]error{
				dst.Close(),
				src.Close(),
			}
			if err != nil {
				return
			} else if err = errors.Join(closeErrs[:]...); err != nil {
				return
			}
		}
	}

	return os.Chmod(etc.String(), 0500)
}

// Kind returns the hardcoded [pkg.Kind] value.
func (cureEtc) Kind() pkg.Kind { return kindEtc }

// Params writes whether iana-etc is populated.
func (a cureEtc) Params(ctx *pkg.IContext) {
	if !a.minimal {
		ctx.WriteUint32(1)
	} else {
		ctx.WriteUint32(0)
	}
}

func init() {
	pkg.Register(kindEtc, func(r *pkg.IRReader) pkg.Artifact {
		a := cureEtc{}
		if r.ReadUint32() == 0 {
			a.minimal = true
		} else {
			r.Next()
		}
		if _, ok := r.Finalise(); ok {
			panic(pkg.ErrUnexpectedChecksum)
		}
		return a
	})
}

// IsExclusive returns false: Cure performs a few trivial filesystem writes.
func (cureEtc) IsExclusive() bool { return false }

// Inputs returns a slice containing the backing iana-etc release.
func (a cureEtc) Inputs() []pkg.Artifact {
	if !a.minimal {
		return []pkg.Artifact{ianaEtc}
	}
	return nil
}

// String returns a hardcoded reporting name.
func (a cureEtc) String() string {
	if a.minimal {
		return "cure-etc-minimal"
	}
	return "cure-etc"
}

// ianaEtc is an unpacked iana-etc release.
var ianaEtc = newFromGitHubRelease(
	"Mic92/iana-etc",
	"20251215",
	"iana-etc-20251215.tar.gz",
	"kvKz0gW_rGG5QaNK9ZWmWu1IEgYAdmhj_wR7DYrh3axDfIql_clGRHmelP7525NJ",
	pkg.Gzip,
)

var (
	resolvconfPath pkg.ExecPath
	resolvconfOnce sync.Once
)

// resolvconf returns a hardcoded /etc/resolv.conf file.
func resolvconf() pkg.ExecPath {
	resolvconfOnce.Do(func() {
		resolvconfPath = pkg.Path(
			fhs.AbsEtc.Append("resolv.conf"), false,
			pkg.NewFile("resolv.conf", []byte(`
nameserver 1.1.1.1
nameserver 1.0.0.1
`)),
		)
	})
	return resolvconfPath
}
