package opsaction

import (
	"context"
	"errors"
	"sync"

	ccent "github.com/tidbcloud/devops/entity/cloudconfig"
	opent "github.com/tidbcloud/devops/entity/operation"
	"github.com/tidbcloud/devops/pkg/service/operation/actions"
)

var (
	ActionSyncGitopsVersions opent.ActionMetadata = opent.ActionMetadata{
		Name: "SyncGitopsVersions",
		Type: opent.ActionTypeAuto,
	}
)

type SyncGitopsVersionsParam struct {
	ClusterType  ccent.ClusterType `json:"cluster_type"`
	GitopsBranch string            `json:"gitops_branch"`
	TierBranch   string            `json:"tier_branch"`
	MinVersion   string            `json:"min_version"`
	MaxVersion   string            `json:"max_version"`
}

func (p SyncGitopsVersionsParam) ToMap() map[opent.ParamName]string {
	return map[opent.ParamName]string{
		opent.ParamName("cluster_type"):  string(p.ClusterType),
		opent.ParamName("gitops_branch"): p.GitopsBranch,
		opent.ParamName("tier_branch"):   p.TierBranch,
		opent.ParamName("min_version"):   p.MinVersion,
		opent.ParamName("max_version"):   p.MaxVersion,
	}
}
func fromParam(m map[opent.ParamName]string) SyncGitopsVersionsParam {
	return SyncGitopsVersionsParam{
		ClusterType:  ccent.ClusterType(m["cluster_type"]),
		GitopsBranch: m["gitops_branch"],
		MinVersion:   m["min_version"],
		MaxVersion:   m["max_version"],
	}

}

type SyncGitopsVersions struct {
	actions.BaseAction
	comps  *actions.Components
	lock   sync.Mutex
	status string
}

func NewSyncGitopsVersions(comps *actions.Components) actions.AutoAction {
	return &SyncGitopsVersions{comps: comps}
}

func (a *SyncGitopsVersions) Metadata() opent.ActionMetadata {
	return ActionSyncGitopsVersions
}

func (a *SyncGitopsVersions) PreCheck(ctx context.Context, instance *opent.Instance) error {
	a.lock.Lock()
	defer a.lock.Unlock()

	if a.status == "running" {
		return errors.New("other task is running")
	}
	return nil
}

func (a *SyncGitopsVersions) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	a.lock.Lock()
	defer a.lock.Unlock()

	if a.status == "running" {
		return actions.FailedActionResult(errors.New("other task is running")), nil
	}
	a.status = "running"

	go func() {
		param := fromParam(instance.Params)
		// Use context.WithoutCancel to detach from the parent context's cancellation signal,
		// since this goroutine outlives the transaction that calls Start().
		bgCtx := context.WithoutCancel(ctx)
		err := a.comps.CloudConfigAPI.SyncVersionsFromGitops(bgCtx, param.MinVersion, param.MaxVersion, param.GitopsBranch)

		a.lock.Lock()
		defer a.lock.Unlock()
		if err != nil {
			a.status = err.Error()
		} else {
			a.status = "succeed"
		}
	}()
	return actions.RunningActionResult("task is running", nil), nil
}

func (a *SyncGitopsVersions) Result(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	a.lock.Lock()
	defer a.lock.Unlock()

	switch a.status {
	case "running":
		return actions.RunningActionResult("task is running", nil), nil
	case "succeed":
		return actions.SucceededActionResult(nil), nil
	case "":
		return actions.FailedActionResult(errors.New("unknown")), nil
	default:
		return actions.FailedActionResult(errors.New(a.status)), nil
	}
}
