package history

import (
	"context"

	"github.com/tidbcloud/account/internel/dao/entity"
	"github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

var _ HistoryDaoIface = (*HistoryDao)(nil)

type EventHistoryFilter struct {
	IdentityIDs    []entity.ID
	IdentityTypes  []entity.HistoryIdentityType
	IdentityValues []string
	Events         []entity.HistoryEvent
	TargetIDs      []entity.ID
	TargetTypes    []entity.HistoryTargetType
}

type SingleEventHistoryFilter struct {
	IdentityID    entity.ID
	IdentityType  entity.HistoryIdentityType
	IdentityValue string
	Event         entity.HistoryEvent
	TargetType    entity.HistoryTarget
	TargetID      entity.ID
}

type HistoryDaoIface interface {
	ListEventHistories(ctx context.Context, tx *gorm.DB, filter EventHistoryFilter) ([]entity.EventHistory, error)
	CreateEventHistory(ctx context.Context, tx *gorm.DB, eventHistory *entity.EventHistory) error

	// EventHistoryLast
	CreateOrUpdateEventHistoryLast(ctx context.Context, tx *gorm.DB, eventHistoryLast *entity.EventHistoryLast) error
	GetLastHistoryLast(ctx context.Context, tx *gorm.DB, filter SingleEventHistoryFilter) (*entity.EventHistoryLast, error)
	ListEventHistoryLast(ctx context.Context, tx *gorm.DB, filter EventHistoryFilter) ([]entity.EventHistoryLast, error)
}

type HistoryDao struct{}

func NewDao() HistoryDaoIface {
	return &HistoryDao{}
}

func (d *HistoryDao) ListEventHistories(ctx context.Context, tx *gorm.DB, filter EventHistoryFilter) ([]entity.EventHistory, error) {
	var objs []entity.EventHistory

	if len(filter.TargetTypes) == 0 && len(filter.TargetIDs) == 0 && len(filter.IdentityValues) == 0 {
		tilog.Info(ctx, "ListEventHistoryFilter is nil ", zap.Error(nil))
		return nil, errs.NewBadRequest("EventHistoryFilter must not null", nil)
	}

	qs := entity.NewEventHistoryQuerySet(tx.Group("target_id"))

	if len(filter.TargetIDs) > 0 {
		qs = qs.TargetIDIn(filter.TargetIDs...)
	}
	if len(filter.TargetTypes) > 0 {
		qs = qs.TargetTypeIn(filter.TargetTypes...)
	}
	if len(filter.IdentityValues) > 0 {
		qs = qs.IdentityValueIn(filter.IdentityValues...)
	}

	if len(filter.Events) > 0 {
		qs = qs.EventIn(filter.Events...)
	}

	qs = qs.OrderDescByCreatedAt()
	err := qs.All(&objs)
	if err != nil && err != gorm.ErrRecordNotFound {
		tilog.Error(ctx, "ListEventHistories fail", zap.Error(err))
		return nil, err
	}
	tilog.Info(ctx, "ListEventHistory ", zap.Any("result", objs), zap.Any("filter", filter))
	return objs, nil
}

func (d *HistoryDao) CreateEventHistory(ctx context.Context, tx *gorm.DB, eventHistory *entity.EventHistory) error {
	err := tx.Create(eventHistory).Error
	if err != nil {
		tilog.Error(ctx, "HistoryDao CreateEventHistory fail: ", zap.Any("history: ", eventHistory), zap.Error(err))
		return err
	}
	tilog.Info(ctx, "HistoryDao CreateEventHistory success: ", zap.Any("history: ", eventHistory))

	return nil
}
