package cluster

import (
	"context"

	"github.com/samber/lo"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	tidbmgmtservicev1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/repository"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (c *serverImpl) BuildComponentSpecDiffReports(
	ctx context.Context,
	req *tidbmgmtservicev1.BuildComponentSpecDiffReportsRequest,
) (*tidbmgmtservicev1.BuildComponentSpecDiffReportsResponse, error) {
	if req.GetPage() < 1 {
		req.Page = 1
	}
	if req.GetPageSize() < 1 {
		req.PageSize = maxPageSize
	}
	if req.GetPageSize() > maxPageSize {
		return nil, bizerr.New(bizerr.ErrCodeParams, "page size is too large")
	}

	clusters, err := c.clusterRepo.QueryClusterByFilterAndPage(
		ctx,
		&repository.ClusterFilter{
			ClusterIds:      req.GetClusterIds(),
			ProjectIds:      req.GetProjectIds(),
			OrganizationIds: req.GetTenantIds(),
			DeployType:      entity.DeployTypeDedicated,
			CloudProviders: lo.Map(
				req.GetCloudProviders(),
				func(p globalcommonv1.CloudProvider_Name, _ int) string { return p.String() },
			),
			Regions: lo.Map(
				req.GetRegions(),
				func(r globalcommonv1.Region_Name, _ int) string { return r.String() },
			),
			View:         entity.ClusterViewClusterViewLocal,
			QueryDeleted: false,
		},
		int((req.GetPage()-1)*req.GetPageSize()),
		int(req.GetPageSize()),
	)
	if err != nil {
		return nil, bizerr.WrapGormError(err, "failed to query clusters")
	}

	if len(clusters) == 0 {
		return &tidbmgmtservicev1.BuildComponentSpecDiffReportsResponse{
			Clusters: []*tidbmgmtservicev1.BuildComponentSpecDiffReportsResponse_Report{},
		}, nil
	}

	clusterMap := lo.Associate(clusters, func(c *entity.Cluster) (uint64, *entity.Cluster) {
		return c.ClusterId, c
	})

	resp, err := c.dedicatedCli.BuildDesiredComponents(ctx, &globaldedicatedv1.BuildDesiredComponentsRequest{
		Target: &globaldedicatedv1.BuildDesiredComponentsRequest_Scan_{
			Scan: &globaldedicatedv1.BuildDesiredComponentsRequest_Scan{
				ClusterIds: lo.Map(clusters, func(c *entity.Cluster, _ int) uint64 { return c.ClusterId }),
			},
		}})
	if err != nil {
		return nil, err
	}

	return &tidbmgmtservicev1.BuildComponentSpecDiffReportsResponse{
		Clusters: lo.Map(
			resp.GetClusterDiffs(),
			func(c *globaldedicatedv1.BuildDesiredComponentsResponse_ClusterDiff, _ int) *tidbmgmtservicev1.BuildComponentSpecDiffReportsResponse_Report {
				return &tidbmgmtservicev1.BuildComponentSpecDiffReportsResponse_Report{
					TenantId:                   clusterMap[c.GetClusterId()].OrganizationId,
					ProjectId:                  clusterMap[c.GetClusterId()].ProjectId,
					ClusterId:                  c.GetClusterId(),
					ClusterName:                clusterMap[c.GetClusterId()].DisplayName,
					CurrentDefaultComponents:   c.GetCurrentDefaultComponents(),
					CurrentEffectiveComponents: c.GetCurrentEffectiveComponents(),
				}
			},
		),
	}, nil
}
