package repository

import (
	"context"
	"github.com/tidbcloud/auth-server/internal/dto"

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

func ListEntitiesByPage[T any](ctx context.Context, tx *gorm.DB, pageParams dto.PageParams) (*dto.Paginator, error) {
	tilog.Info(ctx, "ListEntitiesByPage", zap.Any("pageParams", pageParams))

	pagination, err := Paginate[T](tx, pageParams)

	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[T any](ctx context.Context, db *gorm.DB, params dto.ListParams) ([]T, error) {
	tilog.Info(ctx, "ListEntities", zap.Any("params", params))

	db = applyFilters(db, params.Filters, params.AdvancedFilters)

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

	var data []T
	if err := db.Find(&data).Error; err != nil && err != gorm.ErrRecordNotFound {
		tilog.PlainInfo("error", zap.Error(err))
		return nil, err
	}

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

// GetEntity
func GetEntity[T any](ctx context.Context, db *gorm.DB, comParams dto.ComFilter) (*T, error) {
	db = applyFilters(db, comParams.Filters, comParams.AdvancedFilters)

	var entity T
	var err error
	if err = db.First(&entity).Error; err != nil && err != gorm.ErrRecordNotFound {
		tilog.Info(ctx, "Get entity error", zap.Error(err))
		return nil, err
	}
	if err == gorm.ErrRecordNotFound {
		return nil, nil
	}

	return &entity, nil
}

// UpdateEntity
func UpdateEntity[T any](ctx context.Context, db *gorm.DB, comParams dto.ComFilter, updates map[string]interface{}) error {
	db = applyFilters(db, comParams.Filters, comParams.AdvancedFilters)

	if err := db.Model(new(T)).Updates(updates).Error; err != nil {
		tilog.PlainInfo("Update entity error", zap.Error(err))
		return err
	}
	tilog.Info(ctx, "Update entity success", zap.Any("updates", updates))
	return nil
}

// DeleteEntity
func DeleteEntity[T any](ctx context.Context, db *gorm.DB, comParams dto.ComFilter) error {
	db = applyFilters(db, comParams.Filters, comParams.AdvancedFilters)

	if err := db.Delete(new(T)).Error; err != nil {
		tilog.Error(ctx, "Delete entity error", zap.Error(err))
		return err
	}

	return nil
}

// applyFilters
func applyFilters(db *gorm.DB, filters map[string]interface{}, advancedFilters map[string]interface{}) *gorm.DB {
	// simple filter conditions
	for key, value := range filters {
		db = db.Where(key+" = ?", value)
	}

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

	return db
}
