package steps

import (
	"context"
	"fmt"
	"time"

	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/caselib/pkg/host"
	"go.uber.org/zap"
)

type waitAllWorkerOnline struct {
	dmHost *host.DMHost
}

func (w *waitAllWorkerOnline) Execute(ctx context.Context) error {
	// wait at most for 100 seconds, if a worker is still offline, return error
	for i := 0; i < 20; i++ {
		response, err := w.dmHost.ListMember("--worker")
		if err != nil {
			return err
		}
		if !response.Result || len(response.Members) != 1 || response.Members[0].GetWorker() == nil {
			return errors.Errorf("failed to get worker", zap.Reflect("status", response))
		}
		allOnline := true
		for _, workerInfo := range response.Members[0].GetWorker().Workers {
			if workerInfo == nil || workerInfo.Stage == "offline" {
				allOnline = false
				break
			}
		}
		if allOnline {
			log.Info("waitAllWorkerOnline all worker online")
			return nil
		}
		log.Info(fmt.Sprintf("waitAllWorkerOnline not all worker online for %v time", i+1))
		time.Sleep(time.Second * 5)
	}
	return errors.Errorf("waitAllWorkerOnline failed")
}

func (w *waitAllWorkerOnline) String() string {
	return "waitAllWorkerOnline"
}

func NewWaitAllDmWorkerOnline(dmHost *host.DMHost) *waitAllWorkerOnline {
	return &waitAllWorkerOnline{dmHost}
}

func (b *Builder) DmWaitAllWorkerOnline(dmHost *host.DMHost) *Builder {
	b.steps = append(b.steps, NewWaitAllDmWorkerOnline(dmHost))
	return b
}

type deleteAllDmWorkerRelayDir struct {
	dmHost *host.DMHost
}

func (d *deleteAllDmWorkerRelayDir) Execute(ctx context.Context) error {
	response, err := d.dmHost.ListMember("--worker")
	if err != nil {
		return err
	}
	if !response.Result || len(response.Members) != 1 || response.Members[0].GetWorker() == nil {
		return errors.Errorf("failed to get worker", zap.Reflect("status", response))
	}
	for _, workerInfo := range response.Members[0].GetWorker().Workers {
		err := d.dmHost.DeleteWorkerRelayDir(workerInfo.Name)
		if err != nil {
			return err
		}
		log.Info("deleteDmWorkerRelayDir success", zap.String("worker", workerInfo.Name))
	}
	log.Info("deleteAllDmWorkerRelayDir success")
	return nil
}

func (d *deleteAllDmWorkerRelayDir) String() string {
	return "deleteAllDmWorkerRelayDir"
}

func NewDeleteAllDmWorkerRelayDir(dmHost *host.DMHost) *deleteAllDmWorkerRelayDir {
	return &deleteAllDmWorkerRelayDir{dmHost}
}

func (b *Builder) DmDeleteAllWorkerRelayDir(dmHost *host.DMHost) *Builder {
	b.steps = append(b.steps, NewDeleteAllDmWorkerRelayDir(dmHost))
	return b
}
