package hcs

import (
	"context"
	"io"
	"syscall"

	"github.com/Microsoft/go-winio"
	diskutil "github.com/Microsoft/go-winio/vhd"
	"github.com/Microsoft/hcsshim/computestorage"
	"github.com/pkg/errors"
	"golang.org/x/sys/windows"
)

// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles
// if there is an error.
func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
	fs := make([]io.ReadWriteCloser, len(hs))
	for i, h := range hs {
		if h != syscall.Handle(0) {
			if err == nil {
				fs[i], err = winio.MakeOpenFile(h)
			}
			if err != nil {
				syscall.Close(h)
			}
		}
	}
	if err != nil {
		for _, f := range fs {
			if f != nil {
				f.Close()
			}
		}
		return nil, err
	}
	return fs, nil
}

// CreateNTFSVHD creates a VHD formatted with NTFS of size `sizeGB` at the given `vhdPath`.
func CreateNTFSVHD(ctx context.Context, vhdPath string, sizeGB uint32) (err error) {
	if err := diskutil.CreateVhdx(vhdPath, sizeGB, 1); err != nil {
		return errors.Wrap(err, "failed to create VHD")
	}

	vhd, err := diskutil.OpenVirtualDisk(vhdPath, diskutil.VirtualDiskAccessNone, diskutil.OpenVirtualDiskFlagNone)
	if err != nil {
		return errors.Wrap(err, "failed to open VHD")
	}
	defer func() {
		err2 := windows.CloseHandle(windows.Handle(vhd))
		if err == nil {
			err = errors.Wrap(err2, "failed to close VHD")
		}
	}()

	if err := computestorage.FormatWritableLayerVhd(ctx, windows.Handle(vhd)); err != nil {
		return errors.Wrap(err, "failed to format VHD")
	}

	return nil
}
