package main

import (
	"fmt"
	"log/slog"
	"slices"

	"github.com/urfave/cli/v2"
	"go.uber.org/automaxprocs/maxprocs"
)

type appMode string

const (
	appModeProduction  appMode = "production"
	appModeDevelopment appMode = "development"
)

func (m appMode) String() string {
	return string(m)
}

var (
	appFlagMode = &cli.GenericFlag{
		Name: "mode",
		Value: &EnumValue{
			Enum:    []string{appModeDevelopment.String(), appModeProduction.String()},
			Default: appModeDevelopment.String(),
		},
		Usage:   fmt.Sprintf("%s or %s", appModeProduction, appModeDevelopment),
		EnvVars: []string{"APP_MODE"},
	}
	appFlagAutoMaxProcs = &cli.BoolFlag{
		Name: "autoMaxProcs",
		Usage: "whether to set GOMAXPROCS automatically to match Linux container CPU quota" +
			" (https://github.com/uber-go/automaxprocs)",
		Value:   false,
		EnvVars: []string{"AUTO_MAX_PROCS"},
	}
	appFlags = []cli.Flag{
		appFlagMode,
		appFlagAutoMaxProcs,
	}
)

type appWrapper struct {
	*cli.App
	logger *slog.Logger
}

func newApp(name, version string) *appWrapper {
	app := &appWrapper{App: cli.NewApp(), logger: slog.Default()}
	app.Name = name
	app.HelpName = name
	app.Version = version
	app.Commands = []*cli.Command{cmdDB, cmdJob, cmdConsumer, cmdServe}
	app.DefaultCommand = cmdServe.Name
	app.Flags = slices.Concat(appFlags, logFlags)
	app.Before = app.handleBefore
	return app
}

func (a *appWrapper) handleBefore(c *cli.Context) error {
	a.logger = newLoggerFromFlags(c)

	c.Context = loggerToCtx(c.Context, a.logger)

	if c.Bool(appFlagAutoMaxProcs.Name) {
		_, _ = maxprocs.Set(maxprocs.Logger(func(s string, v ...any) {
			a.logger.Info(fmt.Sprintf(s, v...))
		}))
	}

	a.logger.Debug("executing command", slog.Any("args", c.Args().Slice()))

	return nil
}
