package app

import (
	"context"
	"errors"
	"io"
	"log"
	"os"

	"github.com/peterbourgon/ff/v4"
	"github.com/peterbourgon/ff/v4/ffhelp"
)

const (
	appVersion = "0.5.2"
)

// struct for receivers to use common app pieces
type app struct {
	stdLogger   *log.Logger
	debugLogger *log.Logger
	errLogger   *log.Logger
	cmd         *ff.Command
	config      *config
}

// actual application start
func Start(args []string) {
	// make app w/ logger
	app := &app{
		stdLogger:   log.New(os.Stdout, "", 0),
		debugLogger: log.New(io.Discard, "", 0), // discard debug logging by default
		errLogger:   log.New(os.Stderr, "", 0),
	}

	// log start
	app.stdLogger.Printf("apc-p15-tool v%s", appVersion)

	// get os.Args if args unspecified in func
	if args == nil {
		args = os.Args
	}

	// get & parse config
	err := app.getConfig(args)

	// if debug logging, make real debug logger
	if app.config.debugLogging != nil && *app.config.debugLogging {
		app.debugLogger = log.New(os.Stdout, "debug: ", 0)
	}

	// deal with config err (after logger re-init)
	if err != nil {
		exitCode := 0

		if errors.Is(err, ff.ErrHelp) {
			// help explicitly requested
			app.stdLogger.Printf("\n%s\n", ffhelp.Command(app.cmd))

		} else if errors.Is(err, ff.ErrDuplicateFlag) ||
			errors.Is(err, ff.ErrUnknownFlag) ||
			errors.Is(err, ff.ErrNoExec) ||
			errors.Is(err, ErrExtraArgs) {
			// other error that suggests user needs to see help
			exitCode = 1
			app.errLogger.Print(err)
			app.stdLogger.Printf("\n%s\n", ffhelp.Command(app.cmd))

		} else {
			// any other error
			exitCode = 1
			app.errLogger.Print(err)
		}

		os.Exit(exitCode)
	}

	// run it
	exitCode := 0
	err = app.cmd.Run(context.Background())
	if err != nil {
		exitCode = 1
		app.errLogger.Print(err)

		// if extra args, show help
		if errors.Is(err, ErrExtraArgs) {
			app.stdLogger.Printf("\n%s\n", ffhelp.Command(app.cmd))
		}
	}

	app.stdLogger.Print("apc-p15-tool done")
	os.Exit(exitCode)
}