package cli

import (
	"fmt"
	"os"
	"time"

	"git.eeqj.de/sneak/mfer/internal/log"
	"github.com/urfave/cli/v2"
)

type CLIApp struct {
	appname     string
	version     string
	gitrev      string
	startupTime time.Time
	exitCode    int
	app         *cli.App
}

const banner = `              ___           ___         ___           ___
	     /__/\         /  /\       /  /\         /  /\
	    |  |::\       /  /:/_     /  /:/_       /  /::\
	    |  |:|:\     /  /:/ /\   /  /:/ /\     /  /:/\:\
	  __|__|:|\:\   /  /:/ /:/  /  /:/ /:/_   /  /:/~/:/
	 /__/::::| \:\ /__/:/ /:/  /__/:/ /:/ /\ /__/:/ /:/___
	 \  \:\~~\__\/ \  \:\/:/   \  \:\/:/ /:/ \  \:\/:::::/
	  \  \:\        \  \::/     \  \::/ /:/   \  \::/~~~~
	   \  \:\        \  \:\      \  \:\/:/     \  \:\
	    \  \:\        \  \:\      \  \::/       \  \:\
	     \__\/         \__\/       \__\/         \__\/`

func (mfa *CLIApp) printBanner() {
	fmt.Println(banner)
}

func (mfa *CLIApp) VersionString() string {
	return fmt.Sprintf("%s (%s)", mfa.version, mfa.gitrev)
}

func (mfa *CLIApp) setVerbosity(v int) {
	_, present := os.LookupEnv("MFER_DEBUG")
	if present {
		log.EnableDebugLogging()
	} else {
		log.SetLevelFromVerbosity(v)
	}
}

func (mfa *CLIApp) run() {
	mfa.startupTime = time.Now()

	if NO_COLOR {
		// shoutout to rob pike who thinks it's juvenile
		log.DisableStyling()
	}

	log.Init()

	var verbosity int

	mfa.app = &cli.App{
		Name:                 mfa.appname,
		Usage:                "Manifest generator",
		Version:              mfa.VersionString(),
		EnableBashCompletion: true,
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:    "verbose",
				Usage:   "Verbosity level",
				Aliases: []string{"v"},
				Count:   &verbosity,
			},
			&cli.BoolFlag{
				Name:    "quiet",
				Usage:   "don't produce output except on error",
				Aliases: []string{"q"},
			},
		},
		Commands: []*cli.Command{
			{
				Name:    "generate",
				Aliases: []string{"gen"},
				Usage:   "Generate manifest file",
				Action: func(c *cli.Context) error {
					if !c.Bool("quiet") {
						mfa.printBanner()
					}
					mfa.setVerbosity(verbosity)
					return mfa.generateManifestOperation(c)
				},
				Flags: []cli.Flag{
					&cli.BoolFlag{
						Name:    "FollowSymLinks",
						Aliases: []string{"follow-symlinks"},
						Usage:   "Resolve encountered symlinks",
					},
					&cli.BoolFlag{
						Name:    "IgnoreDotfiles",
						Aliases: []string{"ignore-dotfiles"},
						Usage:   "Ignore any dot (hidden) files encountered",
					},
					&cli.StringFlag{
						Name:    "output",
						Value:   "./index.mf",
						Aliases: []string{"o"},
						Usage:   "Specify output filename",
					},
				},
			},
			{
				Name:  "check",
				Usage: "Validate files using manifest file",
				Action: func(c *cli.Context) error {
					if !c.Bool("quiet") {
						mfa.printBanner()
					}
					mfa.setVerbosity(verbosity)
					return mfa.checkManifestOperation(c)
				},
			},
			{
				Name:  "version",
				Usage: "Show version",
				Action: func(c *cli.Context) error {
					fmt.Printf("%s\n", mfa.VersionString())
					return nil
				},
			},
			{
				Name:  "fetch",
				Usage: "fetch manifest and referenced files",
				Action: func(c *cli.Context) error {
					if !c.Bool("quiet") {
						mfa.printBanner()
					}
					mfa.setVerbosity(verbosity)
					return mfa.fetchManifestOperation(c)
				},
			},
		},
	}

	mfa.app.HideVersion = true
	err := mfa.app.Run(os.Args)
	if err != nil {
		mfa.exitCode = 1
		log.WithError(err).Debugf("exiting")
	}
}
