package main

import (
	"archive/tar"
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"os"

	"novit.tech/direktil/local-server/pkg/utf16"
)

func rmTempFile(f *os.File) {
	f.Close()
	if err := os.Remove(f.Name()); err != nil {
		log.Print("failed to remove ", f.Name(), ": ", err)
	}
}

func buildBootTar(out io.Writer, ctx *renderContext) (err error) {
	arch := tar.NewWriter(out)
	defer arch.Close()

	archAdd := func(path string, ba []byte) (err error) {
		err = arch.WriteHeader(&tar.Header{Name: path, Mode: 0640, Size: int64(len(ba))})
		if err != nil {
			return
		}
		_, err = arch.Write(ba)
		return
	}

	// kernel
	kernelPath, err := ctx.distFetch("kernels", ctx.Host.Kernel)
	if err != nil {
		return
	}

	kernelBytes, err := ioutil.ReadFile(kernelPath)
	if err != nil {
		return
	}

	err = archAdd("current/vmlinuz", kernelBytes)
	if err != nil {
		return
	}

	// initrd
	initrd := new(bytes.Buffer)
	err = buildInitrdV2(initrd, ctx)
	if err != nil {
		return
	}

	err = archAdd("current/initrd", initrd.Bytes())
	if err != nil {
		return
	}

	// done
	return nil
}

func buildBootEFITar(out io.Writer, ctx *renderContext) (err error) {
	arch := tar.NewWriter(out)
	defer arch.Close()

	archAdd := func(path string, ba []byte) (err error) {
		err = arch.WriteHeader(&tar.Header{Name: path, Mode: 0640, Size: int64(len(ba))})
		if err != nil {
			return
		}
		_, err = arch.Write(ba)
		return
	}

	const (
		prefix    = "EFI/dkl/"
		efiPrefix = "\\EFI\\dkl\\"
	)

	// boot.csv
	// -> annoyingly it's UTF-16...
	bootCsvBytes := utf16.FromUTF8([]byte("" +
		"current_kernel.efi,dkl current,initrd=" + efiPrefix + "current_initrd.img,Direktil current\n" +
		"previous_kernel.efi,dkl previous,initrd=" + efiPrefix + "previous_initrd.img,Direktil previous\n"))

	err = archAdd(prefix+"BOOT.CSV", []byte(bootCsvBytes))
	if err != nil {
		return
	}

	// kernel
	kernelPath, err := ctx.distFetch("kernels", ctx.Host.Kernel)
	if err != nil {
		return
	}

	kernelBytes, err := ioutil.ReadFile(kernelPath)
	if err != nil {
		return
	}

	err = archAdd(prefix+"current_kernel.efi", kernelBytes)
	if err != nil {
		return
	}

	// initrd
	initrd := new(bytes.Buffer)
	err = buildInitrdV2(initrd, ctx)
	if err != nil {
		return
	}

	err = archAdd(prefix+"current_initrd.img", initrd.Bytes())
	if err != nil {
		return
	}

	// done
	return nil
}