package tenantaction

import (
	"context"
	"fmt"

	opent "github.com/tidbcloud/devops/entity/operation"
	"github.com/tidbcloud/devops/pkg/service/operation/actions"
	mgmtv1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"google.golang.org/protobuf/encoding/protojson"
)

var (
	ActionCreateReservedCapacityTemplate opent.ActionMetadata = opent.ActionMetadata{
		Name: "CreateReservedCapacityTemplate",
		Type: opent.ActionTypeAuto,
	}
	ActionUpdateReservedCapacityTemplateStatus opent.ActionMetadata = opent.ActionMetadata{
		Name: "UpdateReservedCapacityTemplateStatus",
		Type: opent.ActionTypeAuto,
	}
	ActionDeleteReservedCapacityTemplate opent.ActionMetadata = opent.ActionMetadata{
		Name: "DeleteReservedCapacityTemplate",
		Type: opent.ActionTypeAuto,
	}
)

type createReservedCapacityTemplate struct {
	actions.BaseAction
	comps *actions.Components
}

func NewCreateReservedCapacityTemplate(comps *actions.Components) actions.AutoAction {
	return &createReservedCapacityTemplate{comps: comps}
}

func (a *createReservedCapacityTemplate) Metadata() opent.ActionMetadata {
	return ActionCreateReservedCapacityTemplate
}

func (a *createReservedCapacityTemplate) PreCheck(ctx context.Context, instance *opent.Instance) error {
	_, err := a.getParam(instance)
	return err
}

func (a *createReservedCapacityTemplate) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	req, err := a.getParam(instance)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}
	if _, err := a.comps.CoreSvc.Mgmt.ReservedCapacityTemplate.CreateReservedCapacityTemplate(ctx, req); err != nil {
		return actions.FailedActionResult(err), nil
	}
	return actions.SucceededActionResult(nil), nil
}

func (a *createReservedCapacityTemplate) getParam(instance *opent.Instance) (*mgmtv1.CreateReservedCapacityTemplateRequest, error) {
	data := instance.Params[opent.ParamCreateReservedCapacityTemplateRequest]
	if data == "" {
		return nil, fmt.Errorf("missing %s", opent.ParamCreateReservedCapacityTemplateRequest)
	}

	req := &mgmtv1.CreateReservedCapacityTemplateRequest{}
	if err := protojson.Unmarshal([]byte(data), req); err != nil {
		return nil, fmt.Errorf("unmarshal %s failed: %w", opent.ParamCreateReservedCapacityTemplateRequest, err)
	}
	return req, nil
}

type updateReservedCapacityTemplateStatus struct {
	actions.BaseAction
	comps *actions.Components
}

func NewUpdateReservedCapacityTemplateStatus(comps *actions.Components) actions.AutoAction {
	return &updateReservedCapacityTemplateStatus{comps: comps}
}

func (a *updateReservedCapacityTemplateStatus) Metadata() opent.ActionMetadata {
	return ActionUpdateReservedCapacityTemplateStatus
}

func (a *updateReservedCapacityTemplateStatus) PreCheck(ctx context.Context, instance *opent.Instance) error {
	_, err := a.getParam(instance)
	return err
}

func (a *updateReservedCapacityTemplateStatus) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	req, err := a.getParam(instance)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}
	if _, err := a.comps.CoreSvc.Mgmt.ReservedCapacityTemplate.UpdateReservedCapacityTemplateStatus(ctx, req); err != nil {
		return actions.FailedActionResult(err), nil
	}
	return actions.SucceededActionResult(nil), nil
}

func (a *updateReservedCapacityTemplateStatus) getParam(instance *opent.Instance) (*mgmtv1.UpdateReservedCapacityTemplateStatusRequest, error) {
	data := instance.Params[opent.ParamUpdateReservedCapacityTemplateStatusRequest]
	if data == "" {
		return nil, fmt.Errorf("missing %s", opent.ParamUpdateReservedCapacityTemplateStatusRequest)
	}

	req := &mgmtv1.UpdateReservedCapacityTemplateStatusRequest{}
	if err := protojson.Unmarshal([]byte(data), req); err != nil {
		return nil, fmt.Errorf("unmarshal %s failed: %w", opent.ParamUpdateReservedCapacityTemplateStatusRequest, err)
	}
	return req, nil
}

type deleteReservedCapacityTemplate struct {
	actions.BaseAction
	comps *actions.Components
}

func NewDeleteReservedCapacityTemplate(comps *actions.Components) actions.AutoAction {
	return &deleteReservedCapacityTemplate{comps: comps}
}

func (a *deleteReservedCapacityTemplate) Metadata() opent.ActionMetadata {
	return ActionDeleteReservedCapacityTemplate
}

func (a *deleteReservedCapacityTemplate) PreCheck(ctx context.Context, instance *opent.Instance) error {
	_, err := a.getParam(instance)
	return err
}

func (a *deleteReservedCapacityTemplate) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	req, err := a.getParam(instance)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}
	if _, err := a.comps.CoreSvc.Mgmt.ReservedCapacityTemplate.DeleteReservedCapacityTemplate(ctx, req); err != nil {
		return actions.FailedActionResult(err), nil
	}
	return actions.SucceededActionResult(nil), nil
}

func (a *deleteReservedCapacityTemplate) getParam(instance *opent.Instance) (*mgmtv1.DeleteReservedCapacityTemplateRequest, error) {
	data := instance.Params[opent.ParamDeleteReservedCapacityTemplateRequest]
	if data == "" {
		return nil, fmt.Errorf("missing %s", opent.ParamDeleteReservedCapacityTemplateRequest)
	}

	req := &mgmtv1.DeleteReservedCapacityTemplateRequest{}
	if err := protojson.Unmarshal([]byte(data), req); err != nil {
		return nil, fmt.Errorf("unmarshal %s failed: %w", opent.ParamDeleteReservedCapacityTemplateRequest, err)
	}
	return req, nil
}
