/*

 _
| |
| |__   _ __
| '_ \ | '__|
| | | || |
|_| |_||_|




CLI program written to populate existing edge info configmap with the correct cluster edge id
The cli program can be run like so:

Using Storage Bucket:
eyede useStorage --databaseHost=localhost --databaseName=dev0 --databaseUser=postgres --databasePassword=****
--topLevelProjectID=ret-edge-dev0-foreman --chariotTopic=chariot-rides

Using Database:
eyede useDatabase --databaseHost=localhost --databaseName=dev0 --databaseUser=postgres --databasePassword=****
--topLevelProjectID=ret-edge-dev0-foreman --chariotTopic=chariot-rides

The following flags are required for the cli to run:
databaseHost, databaseName, databaseUser, databasePassword, topLevelProjectID and chariotTopic
The dryRun flag is an optional and defaults to false if not specified.
launchdarklyKey is also an optional flag that defaults to using cluster id if not set.
*/

package main

import (
	"context"
	"database/sql"
	"errors"
	"flag"
	"fmt"
	"os"

	_ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/postgres"
	"github.com/peterbourgon/ff/v3/ffcli"

	populate "edge-infra.dev/hack/tools/hr/populate"
	hrUtils "edge-infra.dev/hack/tools/hr/utils"
	"edge-infra.dev/pkg/edge/api/clients"
	"edge-infra.dev/pkg/edge/api/utils"
	"edge-infra.dev/pkg/lib/cli/commands"
	"edge-infra.dev/pkg/lib/gcp/cloudsql"
)

var (
	fs                           = flag.NewFlagSet("eyede", flag.ExitOnError)
	databaseHost                 = fs.String("databaseHost", os.Getenv("DatabaseHost"), "the host of the database to query")
	databaseName                 = fs.String("databaseName", os.Getenv("DatabaseName"), "the name of the database to query")
	databaseUser                 = fs.String("databaseUser", os.Getenv("DatabaseUser"), "the user of the specified database")
	databasePassword             = fs.String("databasePassword", os.Getenv("DatabasePassword"), "the password of the specified database (optional for iam auth)")
	topLevelProjectID            = fs.String("topLevelProjectID", os.Getenv("TopLevelProjectID"), "the top level project id")
	bqDbName                     = fs.String("bqDbName", os.Getenv("BqDbName"), "the name of the bq table")
	goog                         = fs.String("googleAppCreds", os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"), "goog app creds")
	launchdarklyKey              = fs.String("launchdarklyKey", os.Getenv("LD_KEY"), "launch darkly sdk key")
	errDatabaseHostRequired      = errors.New("error database host is required")
	errDatabaseNameRequired      = errors.New("error database name is required")
	errDatabaseUserRequired      = errors.New("error database user is required")
	errTopLevelProjectIDRequired = errors.New("error top level project id is required")
	errBqName                    = errors.New("error big query table name is required")
)

func main() {
	err := fs.Parse(os.Args[2:])
	if err != nil {
		fmt.Println("Flag parsing error ", err)
		os.Exit(1)
	}
	if err := validateRequiredFlags(); err != nil {
		fmt.Println("Flag validation error ", err)
		os.Exit(1)
	}
	if utils.IsNullOrEmpty(launchdarklyKey) {
		os.Setenv("LD_KEY", *launchdarklyKey)
	}
	if !utils.IsNullOrEmpty(goog) {
		os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", *goog)
	}
	hrConfig := hrUtils.New()
	fmt.Println(`
 _
| |
| |__   _ __
| '_ \ | '__|
| | | || |
|_| |_||_|`)
	fmt.Printf("Connecting to Database: %s with user %s\n", *databaseName, *databaseUser)
	db, err := connectToDatabase()
	if err != nil {
		fmt.Println("db connection error occurred ", err)
		os.Exit(1)
	}
	bqService, err := clients.New(context.Background(), *topLevelProjectID, *bqDbName)
	if err != nil {
		fmt.Println("bq connection error occurred ", err)
		os.Exit(1)
	}
	hrConfig.SetDBConnection(db)
	hrConfig.SetBQClient(bqService)

	pop := hrConfig.Exec("populate", "hr populate", "populate the helm workloads table", *bqDbName, populate.HelmWorkloadsTable, fs)

	cmd := &ffcli.Command{
		Name:       "hr",
		ShortUsage: "hr --databaseHost=localhost --databaseName=dev0 --databaseUser=postgres --databasePassword=**** --topLevelProjectID=ret-dev-foreman --bqDbName=tableName",
		ShortHelp:  "populate edge ids for all clusters",
		Subcommands: []*ffcli.Command{
			pop,
			commands.Version(),
		},
	}
	if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

func validateRequiredFlags() error {
	if utils.IsNullOrEmpty(databaseHost) {
		return errDatabaseHostRequired
	}
	if utils.IsNullOrEmpty(databaseName) {
		return errDatabaseNameRequired
	}
	if utils.IsNullOrEmpty(databaseUser) {
		return errDatabaseUserRequired
	}
	if utils.IsNullOrEmpty(topLevelProjectID) {
		return errTopLevelProjectIDRequired
	}
	if utils.IsNullOrEmpty(bqDbName) {
		return errBqName
	}
	return nil
}

func connectToDatabase() (*sql.DB, error) {
	conn := cloudsql.GCPPostgresConnection(*databaseHost).
		DBName(*databaseName).
		Username(*databaseUser)
	if databasePassword != nil {
		conn.Password(*databasePassword)
	}
	return conn.NewConnection()
}