package hyperone

import (
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"

	"github.com/hashicorp/packer/packer"
)

type CommandWrapper func(string) (string, error)

// ChrootCommunicator works as a wrapper on SSHCommunicator, modyfing paths in
// flight to be run in a chroot.
type ChrootCommunicator struct {
	Chroot     string
	CmdWrapper CommandWrapper
	Wrapped    packer.Communicator
}

func (c *ChrootCommunicator) Start(ctx context.Context, cmd *packer.RemoteCmd) error {
	command := strconv.Quote(cmd.Command)
	chrootCommand, err := c.CmdWrapper(
		fmt.Sprintf("sudo chroot %s /bin/sh -c %s", c.Chroot, command))
	if err != nil {
		return err
	}

	cmd.Command = chrootCommand

	return c.Wrapped.Start(ctx, cmd)
}

func (c *ChrootCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
	dst = filepath.Join(c.Chroot, dst)
	return c.Wrapped.Upload(dst, r, fi)
}

func (c *ChrootCommunicator) UploadDir(dst string, src string, exclude []string) error {
	dst = filepath.Join(c.Chroot, dst)
	return c.Wrapped.UploadDir(dst, src, exclude)
}

func (c *ChrootCommunicator) Download(src string, w io.Writer) error {
	src = filepath.Join(c.Chroot, src)
	return c.Wrapped.Download(src, w)
}

func (c *ChrootCommunicator) DownloadDir(src string, dst string, exclude []string) error {
	src = filepath.Join(c.Chroot, src)
	return c.Wrapped.DownloadDir(src, dst, exclude)
}
