package clustereventconsumer

import (
	"context"
	"errors"
	"fmt"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"github.com/tidbcloud/tiinf/transport/tieventbus"
	"go.uber.org/zap"
	"gorm.io/gorm"

	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/entity"
	eventutil "github.com/tidbcloud/tidb-management-service/utilities/clusterevent"
)

func (c *clusterEventConsumerManagerImp) handleShadowPoolInstanceState(ctx context.Context, e *tieventbus.Event) error {
	eventBody, ok := e.Data.(*eventutil.ClusterEvent)
	if !ok {
		tilog.Warn(ctx, "event is not a ClusterEvent", zap.String("event id", e.ID), zap.Any("event", e))
		return nil
	}

	if eventBody.ClusterType == eventutil.ClusterTypeTidbxResourcePool {
		tilog.Info(ctx,
			"no need to handle cluster events of resource pool",
			zap.Any("event body", eventBody))
		return nil
	}

	tilog.Info(
		ctx,
		"jsm consumer, try to handle event",
		zap.String("event id", e.ID),
		zap.Uint64("cluster id", eventBody.ClusterID),
		zap.String("event type", string(eventBody.EventType)),
	)

	if eventBody.EventType != eventutil.EventTypeCreated {
		tilog.Info(
			ctx,
			"event type not need to handle for shadow pool",
			zap.String("event id", e.ID),
			zap.Uint64("cluster id", eventBody.ClusterID),
			zap.String("event type", string(eventBody.EventType)),
		)
		return nil
	}

	// database not serverless only
	cls, err := c.clusterRepo.GetCluster(ctx, eventBody.ClusterID, true)
	if err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			err = fmt.Errorf("failed to get cluster. cluster id=%d. error=%w", eventBody.ClusterID, err)
			return err
		}

		tilog.Warn(ctx, "cluster not found.", zap.Uint64("cluster id", eventBody.ClusterID))
		return nil
	}

	if cls.ShadowState == entity.ShadowStatePreparing {
		err = c.clusterRepo.UpdateShadowState(ctx, cls.ClusterId, entity.ShadowStatePrepared, entity.ShadowStatePreparing)
		if err != nil {
			tilog.Error(ctx, "failed to update shadow state for cluster.",
				zap.Uint64("cluster id", eventBody.ClusterID),
				zap.Error(err))
			return err
		}
	}

	return nil
}
