//go:build darwin
// +build darwin

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

const (
	defaultPrefix = "/usr/local"
	dockerSock    = "/var/run/docker.sock"
)

var installPrefix string

var rootCmd = &cobra.Command{
	Use:               "podman-mac-helper",
	Short:             "A system helper to manage docker.sock",
	Long:              `podman-mac-helper is a system helper service and tool for managing docker.sock `,
	CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
	SilenceErrors:     true,
}

// Note, this code is security sensitive since it runs under privilege.
// Limit actions to what is strictly necessary, and take appropriate
// safeguards
//
// After installation the service call is ran under launchd in a nowait
// inetd style fashion, so stdin, stdout, and stderr are all pointing to
// an accepted connection
//
// This service is installed once per user and will redirect
// /var/run/docker to the fixed user-assigned unix socket location.
//
// Control communication is restricted to each user specific service via
// unix file permissions

func main() {
	if os.Geteuid() != 0 {
		fmt.Printf("This command must be ran as root via sudo or osascript\n")
		os.Exit(1)
	}

	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
	}
}

func getUserInfo(name string) (string, string, string, error) {
	// We exec id instead of using user.Lookup to remain compat
	// with CGO disabled.
	cmd := exec.Command("/usr/bin/id", "-P", name)
	output, err := cmd.StdoutPipe()
	if err != nil {
		return "", "", "", err
	}

	if err := cmd.Start(); err != nil {
		return "", "", "", err
	}

	entry := readCapped(output)
	elements := strings.Split(entry, ":")
	if len(elements) < 9 || elements[0] != name {
		return "", "", "", errors.New("Could not lookup user")
	}

	return elements[0], elements[2], elements[8], nil
}

func getUser() (string, string, string, error) {
	name, found := os.LookupEnv("SUDO_USER")
	if !found {
		name, found = os.LookupEnv("USER")
		if !found {
			return "", "", "", errors.New("could not determine user")
		}
	}

	_, uid, home, err := getUserInfo(name)
	if err != nil {
		return "", "", "", fmt.Errorf("could not lookup user: %s", name)
	}
	id, err := strconv.Atoi(uid)
	if err != nil {
		return "", "", "", fmt.Errorf("invalid uid for user: %s", name)
	}
	if id == 0 {
		return "", "", "", fmt.Errorf("unexpected root user")
	}

	return name, uid, home, nil
}

// Used for commands that don't return a proper exit code
func runDetectErr(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	errReader, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	err = cmd.Start()
	if err == nil {
		errString := readCapped(errReader)
		if len(errString) > 0 {
			re := regexp.MustCompile(`\r?\n`)
			err = errors.New(re.ReplaceAllString(errString, ": "))
		}
	}

	if werr := cmd.Wait(); werr != nil {
		err = werr
	}

	return err
}

func readCapped(reader io.Reader) string {
	// Cap output
	buffer := make([]byte, 2048)
	n, _ := io.ReadFull(reader, buffer)
	_, _ = io.Copy(ioutil.Discard, reader)
	if n > 0 {
		return string(buffer[:n])
	}

	return ""
}

func addPrefixFlag(cmd *cobra.Command) {
	cmd.Flags().StringVar(&installPrefix, "prefix", defaultPrefix, "Sets the install location prefix")
}

func silentUsage(cmd *cobra.Command, args []string) {
	cmd.SilenceUsage = true
	cmd.SilenceErrors = true
}