package workload

import (
	"net/url"
	"strconv"
	"strings"
	"time"
)

type CMD struct {
	Command string
	Timeout time.Duration
}

type PerfWorkloadParameters struct {
	WorkloadName string
	WorkloadType string
	Threads int
	TableOrWarehouseCount int
	Duration string
	RunStartTime time.Time
	TestbedName string
}
var PerfWorkloadPara PerfWorkloadParameters

func NewCMD(cmd string, timeout time.Duration) *CMD {
	return &CMD{
		Command: cmd,
		Timeout: timeout,
	}
}

type (
	TPCType     int
	CommandType int
)

const (
	TPCC TPCType = iota
	TPCH
)

func (t TPCType) String() string {
	switch t {
	case TPCC:
		return "tpcc"
	case TPCH:
		return "tpch"
	default:
		panic("unsupported workload type")
	}
}

const (
	CommandTypePrepare CommandType = iota
	CommandTypeRun
	CommandTypeCleanUp

	// CommandTypeLoad only use for ycsb based workload
	CommandTypeLoad
)

func (t CommandType) String() string {
	switch t {
	case CommandTypePrepare:
		return "prepare"
	case CommandTypeRun:
		return "run"
	case CommandTypeCleanUp:
		return "cleanup"
	case CommandTypeLoad:
		return "load"
	default:
		panic("unsupported workload stage, only prepare and run now.")
	}
}

type Option interface {
	Parse(dbURL *url.URL) *CMD
	SetCommand(command CommandType)
	GetTableNames() []string
}

type TPCOption struct {
	DB        string
	T         TPCType
	Warehouse int
	Duration  time.Duration
	Threads   int
	Parts     int
	Command   CommandType
}

func (o *TPCOption) Parse(dbURL *url.URL) *CMD {
	var (
		cmd    = "/go-tpc "
		params []string
	)

	params = append(params, o.T.String())
	params = append(params, "--db "+o.DB)
	params = append(params, "--warehouses "+strconv.Itoa(o.Warehouse))
	params = append(params, "-T "+strconv.Itoa(o.Threads))

	params = append(params, "--host "+dbURL.Hostname())
	params = append(params, "--port "+dbURL.Port())

	if o.Parts > 0 {
		params = append(params, "--parts "+strconv.Itoa(o.Parts))
	}

	if o.Command == CommandTypeRun {
		params = append(params, "--time "+o.Duration.String())
	}

	cmd = cmd + strings.Join(params, " ")
	cmd = cmd + " " + o.Command.String()

	timeout := o.Duration + time.Minute*10
	o.GetWorkloadParameters(dbURL)

	return NewCMD(cmd, timeout)
}

func (o *TPCOption) SetCommand(command CommandType) {
	o.Command = command
}

func (o *TPCOption) GetTableNames() []string {
	return []string{
		"item",
		"customer",
		"district",
		"orders",
		"new_order",
		"order_line",
		"history",
		"warehouse",
		"stock",
	}
}

func (o *TPCOption) GetWorkloadParameters(dbURL *url.URL) error {
	PerfWorkloadPara.WorkloadName = "go-tpc"
	PerfWorkloadPara.WorkloadType = o.T.String()
	PerfWorkloadPara.Threads = o.Threads
	PerfWorkloadPara.TableOrWarehouseCount = o.Warehouse
	PerfWorkloadPara.Duration = o.Duration.String()
	PerfWorkloadPara.TestbedName = strings.Split(dbURL.Hostname(), ".")[1]
	PerfWorkloadPara.RunStartTime = time.Now()
	return nil
}