package cidr

import (
	"context"

	"github.com/samber/lo"
	"gorm.io/gorm"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	cidrrepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cidr"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/infra/repoimpl/common"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (p *cidrRepoImp) CreateSecondaryCidr(ctx context.Context, cidr *entity.CIDR) bizerr.BizError {
	wdb := p.dbProvider.WriteDB(ctx)
	region, err := p.loadRegionByNameAndProviderName(
		ctx,
		cidr.BasicRegion.Name,
		cidr.BasicRegion.CloudProviderName,
		cidr.TenantID,
	)
	if err != nil {
		return err
	}

	secondaryCidr := cidrEnToSecondaryCidrModel(cidr, region)
	if rawErr := wdb.Create(secondaryCidr).Error; rawErr != nil {
		return bizerr.WrapGormError(rawErr, "create secondary cidr")
	}
	return nil
}

func (p *cidrRepoImp) QuerySecondaryCidrs(
	ctx context.Context,
	filter *cidrrepo.Filter,
	sorters []*globaldedicatedv1.Sorter,
) ([]*entity.CIDR, bizerr.BizError) {
	rdb := p.dbProvider.ReadDB(ctx)
	tx := buildTxBySecondaryCidrFilter(buildSecondaryCidrGetter(rdb), filter)
	tx = common.SetOrderByIntoTx(tx, sorters)

	var cidrList []*schema.SecondaryCidr
	if err := tx.Model(&schema.SecondaryCidr{}).Preload("Region").Preload("Provider").Find(&cidrList).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "find secondary cidrs")
	}

	var out []*entity.CIDR
	for _, each := range cidrList {
		cidrEntity, err := secondaryCidrModelToEn(each)
		if err != nil {
			return nil, err
		}
		out = append(out, cidrEntity)
	}
	return out, nil
}

func buildSecondaryCidrGetter(tx *gorm.DB) *gorm.DB {
	return tx.Model(&schema.SecondaryCidr{})
}

func buildTxBySecondaryCidrFilter(tx *gorm.DB, filter *cidrrepo.Filter) *gorm.DB {
	if filter == nil {
		return tx
	}
	if len(filter.IDs) != 0 {
		tx = tx.Where("`secondary_cidrs`.`id` IN (?)", filter.IDs)
	}
	if len(filter.ProjectIDs) != 0 {
		tx = tx.Where("`secondary_cidrs`.`project_id` IN (?)", filter.ProjectIDs)
	}
	if len(filter.RegionNames) != 0 {
		tx = tx.Where(
			"`Region`.`region_name` IN (?)",
			lo.Map(filter.RegionNames, func(i globalcommonv1.Region_Name, _ int) string { return i.String() }),
		)
	}
	if len(filter.CloudProviderNames) != 0 {
		tx = tx.Where(
			"`Provider`.`name` IN (?)",
			lo.Map(
				filter.CloudProviderNames,
				func(i globalcommonv1.CloudProvider_Name, _ int) string { return i.String() },
			),
		)
	}
	if len(filter.OrganizationIds) != 0 {
		tx = tx.Where("`secondary_cidrs`.`tenant_id` IN (?)", filter.OrganizationIds)
	}
	if len(filter.VpcIDs) != 0 {
		tx = tx.Where("`secondary_cidrs`.`vpc_id` IN (?)", filter.VpcIDs)
	}
	return tx
}
