package comdao

import (
	"context"
	"reflect"

	"github.com/tidbcloud/account/internel/dto"

	"github.com/tidbcloud/account/central/utils"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

func ListEntitiesByPage(ctx context.Context, tx *gorm.DB, pageParams dto.PageParams, model interface{}) (*utils.Paginator, error) {
	tilog.Info(ctx, "ListEntitiesByPage", zap.Any("pageParams", pageParams))

	//pagination, err := utils.Paginate(tx, queryParams, &entity.Project{})
	pagination, err := utils.Paginate(tx, pageParams, model)

	if err != nil {
		tilog.Error(ctx, "failed to ListEntitiesByPage", zap.Error(err))
		return nil, err
	}
	tilog.Info(ctx, "ListEntitiesByPage", zap.Any("TotalPages.", pagination.TotalPages), zap.Any("Total", pagination.Total))
	return pagination, nil
}

func ListEntities(ctx context.Context, db *gorm.DB, params dto.ListParams, model interface{}) (interface{}, error) {
	tilog.Info(ctx, "ListEntities", zap.Any("params", params))

	// simple filter conditions
	for key, value := range params.Filters {
		db = db.Where(key+" = ?", value)
	}

	// advanced filter conditions
	for key, value := range params.AdvancedFilters {
		db = db.Where(key, value)
	}

	if params.SortBy != "" && params.Order != "" {
		db = db.Order(params.SortBy + " " + params.Order)
	}

	// Get the type of the model
	elementType := reflect.TypeOf(model).Elem()
	sliceType := reflect.SliceOf(elementType)

	// Use reflect.MakeSlice to create an empty slice of type
	data := reflect.MakeSlice(sliceType, 0, 0).Interface()

	// Execute the query with pagination
	if err := db.Find(&data).Error; err != nil {
		tilog.PlainInfo("error", zap.Error(err))
		return nil, err
	}

	tilog.Info(ctx, "ListEntities success")
	return data, nil
}

// GetEntity  get one entity
func GetEntity(ctx context.Context, db *gorm.DB, params dto.ComFilter, model interface{}) (interface{}, error) {

	db = doFilter(params, db)
	if err := db.First(model).Error; err != nil {
		tilog.PlainInfo("Get entity error", zap.Error(err))
		return nil, err
	}

	return model, nil
}

// UpdateEntity  update one entity
func UpdateEntity(ctx context.Context, db *gorm.DB, comParams dto.ComFilter, updates map[string]interface{}, model interface{}) error {

	db = doFilter(comParams, db)
	if err := db.Model(model).Updates(updates).Error; err != nil {
		tilog.PlainInfo("Update entity error", zap.Error(err))
		return err
	}

	return nil
}

func DeleteEntity(ctx context.Context, db *gorm.DB, params dto.ComFilter, model interface{}) error {

	db = doFilter(params, db)
	if err := db.Delete(model).Error; err != nil {
		tilog.PlainInfo("Delete entity error", zap.Error(err))
		return err
	}

	return nil
}

func doFilter(params dto.ComFilter, db *gorm.DB) *gorm.DB {
	// simple filter conditions
	for key, value := range params.Filters {
		db = db.Where(key+" = ?", value)
	}

	// advanced filter conditions
	for key, value := range params.AdvancedFilters {
		db = db.Where(key, value)
	}

	return db
}
