package cmdstr_test

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/pingcap/endless/pkg/workloadnode/cmdstr"
)

var _ = Describe("Goycsb", func() {

	It("should has correct string reprensentation", func() {
		goycsbCmdString := cmdstr.NewGoycsb("/go-ycsb").
			Run("mysql").
			String()
		Expect(goycsbCmdString).To(Equal("/go-ycsb run mysql"))
	})

	It("should work with GoycsbOptions", func() {
		var opts cmdstr.GoycsbCommonOptions
		opts.Threads = 100
		opts.MySQL.Host = "8.8.8.8"
		goycsbCmdString := cmdstr.NewGoycsb("/go-ycsb").
			Run("xx").
			CommonOptions(&opts).
			String()
		Expect(goycsbCmdString).To(ContainSubstring(`-p threadcount=100`))
		Expect(goycsbCmdString).To(ContainSubstring(`-p mysql.host=8.8.8.8`))
	})

	Context("use BettingOptions", func() {
		var (
			opts    cmdstr.BettingOptions
			flagSet *flag.FlagSet
		)
		BeforeEach(func() {
			flagSet = flag.NewFlagSet("test", flag.ContinueOnError)
			opts.BindFlagSet(flagSet)
		})

		It("should has correct string reprensentation", func() {
			goycsbCmdString := cmdstr.NewGoycsb("/go-ycsb").
				Run("mysql").
				BettingOptions(&opts).
				String()
			Expect(goycsbCmdString).NotTo(ContainSubstring("%!"))
		})

		Context("use BindFlagSet", func() {
			It("should parse flags correctly ", func() {
				host := "example.com"
				dbNamePrefix := "betting_"
				threads := 20
				options := []string{
					"--betting.threads", fmt.Sprintf("%d", threads),
					"--betting.mysql.host", host,
					"--betting.dbnameprefix", dbNamePrefix,
				}
				err := flagSet.Parse(options)
				Expect(err).To(BeNil())
				Expect(opts.Threads).To(Equal(threads))
				Expect(opts.MySQL.Host).To(Equal(host))
				Expect(opts.DBNamePrefix).To(Equal(dbNamePrefix))
			})
			It("should raise error when there is unknown options", func() {
				options := []string{
					"--mysql.host", "xx",
				}
				// Prevent error message to pollute the output.
				flagSet.SetOutput(io.Discard)
				err := flagSet.Parse(options)
				Expect(err).NotTo(BeNil())
			})
		})
	})

	Context("use QHAdOptions", func() {
		var (
			opts    cmdstr.QHAdOptions
			flagSet *flag.FlagSet
		)
		BeforeEach(func() {
			flagSet = flag.NewFlagSet("test", flag.ContinueOnError)
			opts.BindFlagSet(flagSet)
		})
		Context("use BindFlagSet", func() {
			It("should parse flags correctly ", func() {
				host := "example.com"
				threads := 20
				tprefix := "t_"
				options := []string{
					"--qhad.threads", fmt.Sprintf("%d", threads),
					"--qhad.mysql.host", host,
					"--qhad.autocommit",
					"--qhad.tablenameprefix", tprefix,
					"--qhad.exectime", "2m",
				}
				err := flagSet.Parse(options)
				Expect(err).To(BeNil())

				Expect(opts.Threads).To(Equal(threads))
				Expect(opts.MySQL.Host).To(Equal(host))
				Expect(opts.AutoCommit).To(BeTrue())
				Expect(opts.ExecTime.Duration).To(Equal(2 * time.Minute))
				Expect(opts.TableNamePrefix).To(Equal(tprefix))
			})
		})

		It("should has correct string reprensentation", func() {
			goycsbCmdString := cmdstr.NewGoycsb("/go-ycsb").
				Run("mysql").
				QHAdOptions(&opts).
				String()
			Expect(goycsbCmdString).NotTo(ContainSubstring("%!"))
		})

		It("can be unmarshal from json", func() {
			jsBytes := []byte(`
{
	"mysql": {
		"host": "1.1.1.1",
		"port": "1111"
	},
	"threadcount": 50,
	"operationCount": 10000,
	"recordCount": 100,
	"dbName": "test_oncall2929",
	"initialPartitionCount": 7,
	"autoCommit": true,
	"tableCount": 10,
	"tableNamePrefix": "qhad_",
	"dropPartitionInterval": "5s",
	"execTime": "1m"
}`)
			err := json.Unmarshal(jsBytes, &opts)
			Expect(err).To(BeNil())
			Expect(opts.MySQL.Host).To(Equal("1.1.1.1"))
			Expect(opts.InitialPartitionCount).To(Equal(7))
		})
	})
})
