package flag

import (
	"flag"
	"fmt"
	"os"

	"git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/api"
	"git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common"
)

var (
	GenerateCommandHandles = map[string]func(*flag.FlagSet) error{
		"entity":   handleEntityCommand,
		"resource": handleResourceCommand,
	}
	Command                 string
	Mode, Out, BuildProfile *string
	String                  = flag.String
	Bool                    = flag.Bool
	Parse                   = flag.Parse
	Arg                     = flag.Arg
	Args                    = flag.Args
	NewFlagSet              = flag.NewFlagSet
	ExitOnError             = flag.ExitOnError
	PanicOnError            = flag.PanicOnError
	ContinueOnError         = flag.ContinueOnError
	GenerateEntityControl   = struct {
		Name       string
		Type       string
		Properties string
	}{}
	GenerateResourceControl = struct {
		Name    string
		Entity  string
		Methods string
	}{}
	compileFlags, generateFlags *flag.FlagSet
)

type FlagSet = flag.FlagSet

func Initialize() (err error) {

	defer func() {
		if err != nil {
			api.LogInfo(0, "eon [init|compile|serve] ...options")
			api.LogError(0, err.Error())
			flag.PrintDefaults()
		}
	}()

	Out = flag.String("out", "../build", "Target directory of the compilation.")

	// todo add list of valid commands on erro
	Command = os.Args[1]

	switch Command {
	case "init":
	case "g":
		err = generateCommandParse()
	case "compile":
		err = generateCompileParse()
	case "serve":
		err = generateServeParse()

	default:
		fmt.Printf("%q is not valid command.\n", Command)
		os.Exit(2)
	}

	return
}

func generateServeParse() (err error) {
	compileFlags = flag.NewFlagSet("serve", flag.ExitOnError)
	Mode = compileFlags.String("mode", "", "Defines the data source used to compile the project.")
	// Mode = compileFlags.String("mode", "", "Defines the data source used to compile the project.")
	// BuildProfile = compileFlags.String("build", "", "Profile of build functions.")

	compileFlags.Parse(os.Args[2:])

	if compileFlags.Parsed() {
		return
	}

	err = fmt.Errorf("Error....")
	return
}

func generateCompileParse() (err error) {
	compileFlags = flag.NewFlagSet("compile", flag.ExitOnError)

	Mode = compileFlags.String("mode", "", "Defines the data source used to compile the project.")
	BuildProfile = compileFlags.String("build", "", "Profile of build functions.")

	compileFlags.Parse(os.Args[2:])

	if compileFlags.Parsed() {
		return
	}

	err = fmt.Errorf("Error....")
	return
}

func generateCommandParse() (err error) {
	generateFlags = flag.NewFlagSet("g", flag.ExitOnError)

	command := os.Args[2]

	if fn, exist := GenerateCommandHandles[command]; exist {

		if err = fn(generateFlags); err != nil {
			return
		}

		if generateFlags.Parsed() {
			return
		}
	}

	err = fmt.Errorf("Error....")
	return
}

func handleResourceCommand(generateFlags *flag.FlagSet) (err error) {
	Command = "g.resource"
	generateFlags.StringVar(&GenerateResourceControl.Entity, "entity", "", "Entity ")
	generateFlags.StringVar(&GenerateResourceControl.Methods, "methods", "", "Comma-separated list of resource methods.")
	GenerateResourceControl.Name = common.LcFirst(os.Args[3])
	generateFlags.Parse(os.Args[4:])
	return
}

func handleEntityCommand(generateFlags *flag.FlagSet) (err error) {
	Command = "g.entity"
	generateFlags.StringVar(&GenerateEntityControl.Type, "type", "object", "Type of entity. [object, nested.object, abstract]")
	generateFlags.StringVar(&GenerateEntityControl.Properties, "properties", "", "Comma-separated list of structure properties.")
	GenerateEntityControl.Name = common.LcFirst(os.Args[3])
	generateFlags.Parse(os.Args[4:])
	return
}
