package main

import (
	"errors"
	"fmt"
	"isle/daemon/daecommon"
	"os"
	"path/filepath"
	"syscall"
)

// minio-client keeps a configuration directory which contains various pieces of
// information which may or may not be useful. Unfortunately when it initializes
// this directory it likes to print some annoying logs, so we pre-initialize in
// order to prevent it from doing so.
func initMCConfigDir(envVars daecommon.EnvVars) (string, error) {
	var (
		path           = filepath.Join(envVars.StateDir.Path, "mc")
		sharePath      = filepath.Join(path, "share")
		configJSONPath = filepath.Join(path, "config.json")
	)

	if err := os.MkdirAll(sharePath, 0700); err != nil {
		return "", fmt.Errorf("creating %q: %w", sharePath, err)
	}

	if err := os.WriteFile(configJSONPath, []byte(`{}`), 0600); err != nil {
		return "", fmt.Errorf("writing %q: %w", configJSONPath, err)
	}

	return path, nil
}

var subCmdGarageMC = subCmd{
	name:  "mc",
	descr: "Runs the mc (minio-client) binary. The isle garage can be accessed under the `garage` alias",
	do: func(ctx subCmdCtx) error {
		keyID := ctx.flags.StringP(
			"key-id", "i", "",
			"Optional key ID to use, defaults to that of the shared global key",
		)

		keySecret := ctx.flags.StringP(
			"key-secret", "s", "",
			"Optional key secret to use, defaults to that of the shared global key",
		)

		ctx, err := ctx.withParsedFlags(&withParsedFlagsOpts{
			passthroughArgs: true,
		})
		if err != nil {
			return fmt.Errorf("parsing flags: %w", err)
		}

		clientParams, err := ctx.daemonRPC.GetGarageClientParams(ctx)
		if err != nil {
			return fmt.Errorf("calling GetGarageClientParams: %w", err)
		}

		s3APIAddr := clientParams.Node.S3APIAddr()

		if *keyID == "" {
			*keyID = clientParams.GlobalBucketS3APICredentials.ID
		}

		if *keySecret == "" {
			*keySecret = clientParams.GlobalBucketS3APICredentials.Secret
		}

		args := ctx.flags.Args()

		if i := ctx.flags.ArgsLenAtDash(); i >= 0 {
			args = args[i:]
		}

		envVars := daecommon.GetEnvVars()

		configDir, err := initMCConfigDir(envVars)
		if err != nil {
			return fmt.Errorf("initializing minio-client config directory: %w", err)
		}

		args = append([]string{
			binPath("mc"),
			"--config-dir", configDir,
		}, args...)

		var (
			mcHostVar = fmt.Sprintf(
				"MC_HOST_garage=http://%s:%s@%s",
				*keyID, *keySecret, s3APIAddr,
			)

			binPath = binPath("mc")
			cliEnv  = append(
				os.Environ(),
				mcHostVar,

				// The garage docs say this is necessary, though nothing bad
				// seems to happen if we leave it out *shrug*
				"MC_REGION=garage",
			)
		)

		if err := syscall.Exec(binPath, args, cliEnv); err != nil {
			return fmt.Errorf(
				"calling exec(%q, %#v, %#v): %w",
				binPath, args, cliEnv, err,
			)
		}

		return nil
	},
}

var subCmdGarageCLI = subCmd{
	name:  "cli",
	descr: "Runs the garage binary, automatically configured to point to the garage sub-process of a running isle daemon",
	do: func(ctx subCmdCtx) error {
		ctx, err := ctx.withParsedFlags(&withParsedFlagsOpts{
			passthroughArgs: true,
		})
		if err != nil {
			return fmt.Errorf("parsing flags: %w", err)
		}

		clientParams, err := ctx.daemonRPC.GetGarageClientParams(ctx)
		if err != nil {
			return fmt.Errorf("calling GetGarageClientParams: %w", err)
		}

		if clientParams.RPCSecret == "" {
			return errors.New("this host does not have the garage RPC secret")
		}

		var (
			binPath = binPath("garage")
			args    = append([]string{"garage"}, ctx.opts.args...)
			cliEnv  = append(
				os.Environ(),
				"GARAGE_RPC_HOST="+clientParams.Node.RPCNodeAddr(),
				"GARAGE_RPC_SECRET="+clientParams.RPCSecret,
			)
		)

		if err := syscall.Exec(binPath, args, cliEnv); err != nil {
			return fmt.Errorf(
				"calling exec(%q, %#v, %#v): %w",
				binPath, args, cliEnv, err,
			)
		}

		return nil
	},
}

var subCmdGarage = subCmd{
	name:  "garage",
	descr: "Runs the garage binary, automatically configured to point to the garage sub-process of a running isle daemon",
	do: func(ctx subCmdCtx) error {
		return ctx.doSubCmd(
			subCmdGarageCLI,
			subCmdGarageMC,
		)
	},
}