package ngoperation

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	nextgenv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"

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

var ActionOverrideFlexibleBackupRetention = opent.ActionMetadata{
	Name: "OverrideFlexibleBackupRetention",
	Type: opent.ActionTypeAuto,
}

var _ actions.Action = (*overrideFlexibleBackupRetention)(nil)

type flexibleBackupRetentionClient interface {
	OverrideFlexibleBackupRetention(context.Context, *nextgenv1.OverrideFlexibleBackupRetentionRequest) (*nextgenv1.BackupSetting, error)
}

// overrideFlexibleBackupRetention provides the tightly-scoped operational
// override used to shorten flexible-backup retention during incident handling.
// It accepts 1-33 days. Compared with the public API, the internal action also
// permits one- and two-day retention for incident handling.
type overrideFlexibleBackupRetention struct {
	actions.BaseAction
	comps        *actions.Components
	backupClient flexibleBackupRetentionClient
}

func NewOverrideFlexibleBackupRetention(comps *actions.Components) actions.AutoAction {
	return &overrideFlexibleBackupRetention{comps: comps}
}

func (a *overrideFlexibleBackupRetention) Metadata() opent.ActionMetadata {
	return ActionOverrideFlexibleBackupRetention
}

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

func (a *overrideFlexibleBackupRetention) 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.getBackupClient().OverrideFlexibleBackupRetention(ctx, req); err != nil {
		return actions.FailedActionResult(err), nil
	}

	return actions.SucceededActionResult(nil), nil
}

func (a *overrideFlexibleBackupRetention) getBackupClient() flexibleBackupRetentionClient {
	if a.backupClient != nil {
		return a.backupClient
	}
	return a.comps.CoreSvc.Mgmt
}

func (a *overrideFlexibleBackupRetention) Result(_ context.Context, _ *opent.Instance) (*actions.ActionResult, error) {
	return actions.SucceededActionResult(nil), nil
}

func (a *overrideFlexibleBackupRetention) getParam(instance *opent.Instance) (*nextgenv1.OverrideFlexibleBackupRetentionRequest, error) {
	clusterID, exists := instance.GetParam(opent.ParamClusterID)
	if !exists || clusterID == "" {
		return nil, fmt.Errorf("missing cluster ID")
	}
	if _, err := strconv.ParseUint(clusterID, 10, 64); err != nil {
		return nil, fmt.Errorf("invalid cluster ID: %w", err)
	}

	retentionDaysText, exists := instance.GetParam(opent.ParamBackupRetentionDays)
	if !exists || retentionDaysText == "" {
		return nil, fmt.Errorf("missing retention_days")
	}
	retentionDays, err := strconv.ParseInt(retentionDaysText, 10, 32)
	if err != nil {
		return nil, fmt.Errorf("invalid retention_days: %w", err)
	}
	if retentionDays < 1 || retentionDays > 33 {
		return nil, fmt.Errorf("retention_days must be between 1 and 33")
	}

	reason, exists := instance.GetParam(opent.ParamBackupRetentionReason)
	reason = strings.TrimSpace(reason)
	if !exists || reason == "" {
		return nil, fmt.Errorf("missing reason")
	}

	return &nextgenv1.OverrideFlexibleBackupRetentionRequest{
		ClusterId:     clusterID,
		RetentionDays: int32(retentionDays),
		Reason:        reason,
	}, nil
}
