package repo

import (
	"strings"

	tntent "github.com/tidbcloud/devops/entity/tenant"
	"github.com/tidbcloud/devops/pkg/infra/utils/container"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"

	"gorm.io/gorm"
)

func InIds(ids []uint64) repoopt.Option {
	return &repoopt.Filter[uint64]{
		Column: "id",
		Values: ids,
	}
}

func InPlan(plans []tntent.TenantPlan) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "plan",
		Values: container.TransformSlice(plans, container.ToString[tntent.TenantPlan]),
	}
}

func InSalesOwnerEmail(emails []string) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "sales_owner_email",
		Values: emails,
	}
}

func InStatus(status []tntent.TenantStatus) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "status",
		Values: container.TransformSlice(status, container.ToString[tntent.TenantStatus]),
	}
}

func InSegmentation(segmentations []tntent.TenantSegmentation) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "segmentation",
		Values: container.TransformSlice(segmentations, container.ToString[tntent.TenantSegmentation]),
	}
}

func InKind(kinds []tntent.TenantKind) repoopt.Option {
	return &TenantKindFilter{
		Kind: container.TransformSlice(kinds, container.ToString[tntent.TenantKind]),
	}
}

func InRegion(regions []tntent.TenantRegion) repoopt.Option {
	return &TenantRegionFilter{
		Region: container.TransformSlice(regions, container.ToString[tntent.TenantRegion]),
	}
}

func Search(search string) repoopt.Option {
	return &TenantSearch{
		Search: search,
	}
}

type TenantSearch struct {
	Search string
}

func (t *TenantSearch) Apply(db *gorm.DB) *gorm.DB {
	if t == nil {
		return db
	}
	if len(t.Search) > 0 {
		db = db.Where("id = ? OR lower(name) LIKE ? OR lower(email) like ? OR lower(alias) like ?",
			t.Search,
			"%"+strings.ToLower(t.Search)+"%",
			"%"+strings.ToLower(t.Search)+"%",
			"%"+strings.ToLower(t.Search)+"%",
		)
	}
	return db
}

type TenantRegionFilter struct {
	Region []string
}

func (t *TenantRegionFilter) Apply(db *gorm.DB) *gorm.DB {
	if t == nil {
		return db
	}
	upperRegion := container.TransformSlice(t.Region, func(s string) string {
		return strings.ToUpper(s)
	})
	if len(t.Region) > 0 {
		db = db.Where("sales_force_region IN ? OR (sales_force_region = ? AND country_region IN ?)",
			upperRegion,
			"",
			upperRegion,
		)
	}
	return db
}

type TenantKindFilter struct {
	Kind []string
}

func (t *TenantKindFilter) Apply(db *gorm.DB) *gorm.DB {
	if t == nil {
		return db
	}
	lowerKind := container.TransformSlice(t.Kind, func(s string) string {
		return strings.ToLower(s)
	})
	if len(t.Kind) > 0 {
		db = db.Where("sales_force_kind IN ? OR (sales_force_kind = ? AND kind IN ?)",
			lowerKind,
			"",
			lowerKind,
		)
	}
	return db
}

func WithPager(page int, perPage int) repoopt.Option {
	pager := &repoopt.Pager{
		Page:    page,
		PerPage: perPage,
	}
	return pager
}

type OrderColumn string

const (
	OrderColumnCreatedAt OrderColumn = "created_at"
)

func WithOrder(column OrderColumn, desc bool) repoopt.Option {
	return &repoopt.Order{
		Column: string(column),
		Desc:   desc,
	}
}

func DefaultOrder() repoopt.Option {
	return &repoopt.Order{
		Column: "id",
		Desc:   false,
	}
}
