package commands

import (
	"context"
	"flag"
	"os"

	"github.com/google/subcommands"
	c "github.com/kotakanbe/go-cve-dictionary/config"
	"github.com/kotakanbe/go-cve-dictionary/db"
	log "github.com/kotakanbe/go-cve-dictionary/log"
	server "github.com/kotakanbe/go-cve-dictionary/server"
	"github.com/kotakanbe/go-cve-dictionary/util"
)

// ServerCmd is Subcommand for CVE dictionary HTTP Server
type ServerCmd struct {
	debug    bool
	debugSQL bool
	quiet    bool
	logDir   string
	logJSON  bool

	dbpath string
	dbtype string
	bind   string
	port   string
}

// Name return subcommand name
func (*ServerCmd) Name() string { return "server" }

// Synopsis return synopsis
func (*ServerCmd) Synopsis() string { return "Start CVE dictionary HTTP server" }

// Usage return usage
func (*ServerCmd) Usage() string {
	return `server:
	server
		[-bind=127.0.0.1]
		[-port=8000]
		[-dbpath=$PWD/cve.sqlite3 or connection string]
		[-dbtype=mysql|postgres|sqlite3|redis]
		[-debug]
		[-debug-sql]
		[-quiet]
		[-log-dir=/path/to/log]
		[-log-json]

`
}

// SetFlags set flag
func (p *ServerCmd) SetFlags(f *flag.FlagSet) {
	f.BoolVar(&p.debug, "debug", false, "debug mode (default: false)")
	f.BoolVar(&p.debugSQL, "debug-sql", false, "SQL debug mode (default: false)")
	f.BoolVar(&p.quiet, "quiet", false, "quiet mode (no output)")

	defaultLogDir := util.GetDefaultLogDir()
	f.StringVar(&p.logDir, "log-dir", defaultLogDir, "/path/to/log")
	f.BoolVar(&p.logJSON, "log-json", false, "output log as JSON")

	pwd := os.Getenv("PWD")
	f.StringVar(&p.dbpath, "dbpath", pwd+"/cve.sqlite3",
		"/path/to/sqlite3 or SQL connection string")

	f.StringVar(&p.dbtype, "dbtype", "sqlite3",
		"Database type to store data in (sqlite3, mysql, postgres or redis supported)")

	f.StringVar(&p.bind,
		"bind",
		"127.0.0.1",
		"HTTP server bind to IP address (default: loop back interface)")
	f.StringVar(&p.port, "port", "1323",
		"HTTP server port number (default: 1323)")
}

// Execute execute
func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
	c.Conf.Debug = p.debug
	c.Conf.Quiet = p.quiet
	log.SetLogger(p.logDir, c.Conf.Quiet, c.Conf.Debug, p.logJSON)

	c.Conf.DebugSQL = p.debugSQL
	c.Conf.Bind = p.bind
	c.Conf.Port = p.port
	c.Conf.DBPath = p.dbpath
	c.Conf.DBType = p.dbtype

	if !c.Conf.Validate() {
		return subcommands.ExitUsageError
	}

	driver, locked, err := db.NewDB(c.Conf.DBType, c.Conf.DBPath, c.Conf.DebugSQL)
	if err != nil {
		if locked {
			log.Errorf("Failed to Open DB. Close DB connection: %s", err)
			return subcommands.ExitFailure
		}
		log.Errorf("%s", err)
		return subcommands.ExitFailure
	}
	defer driver.CloseDB()

	var count int
	if count, err = driver.CountNvd(); err != nil {
		log.Errorf("Failed to count NVD table: %s", err)
		return subcommands.ExitFailure
	}

	if count == 0 {
		log.Infof("No Vulnerability data found. Run the below command to fetch data from NVD")
		log.Infof("")
		log.Infof(" for i in `seq 2002 $(date +\"%%Y\")`; do go-cve-dictionary fetchnvd -years $i ; done")
		log.Infof("")
		return subcommands.ExitSuccess
	}

	log.Infof("Starting HTTP Server...")
	if err = server.Start(p.logDir, driver); err != nil {
		log.Errorf("%s", err)
		return subcommands.ExitFailure
	}
	return subcommands.ExitSuccess
}
