package monitor

import (
	"context"
	"fmt"

	rbacsvc "github.com/tidbcloud/account/internel/svc/rbac"

	"github.com/tidbcloud/account/thirdparty/mgmt"
	mgmtv1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"

	"github.com/tidbcloud/account/commons/database"
	"github.com/tidbcloud/account/internel/dao"
	"github.com/tidbcloud/account/internel/dao/entity"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

func MonitorClusterRelations(ctx context.Context) error {
	tilog.Info(ctx, "monitor cluster relations start")
	var start uint64 = 0
	var limit = 50
	for {
		tilog.Info(ctx, fmt.Sprintf("monitor cluster relations get start id: %d", start))
		relations, err := dao.GetDaoHub().ResourceRelation.BatchListResourceRelations(ctx, database.DBConn.DB, start, limit)
		if err != nil {
			tilog.Error(ctx, "monitor cluster relations batch list refs error", zap.Any("err", err))
			return err
		}
		if len(relations) == 0 {
			tilog.Info(ctx, "monitor cluster relations over")
			return nil
		}
		for _, relation := range relations {
			// set the max id to start
			if relation.ID.Uint64() > start {
				start = relation.ID.Uint64()
			}
		}
		_ = monitorRelations(ctx, relations)
	}
}

func monitorRelations(ctx context.Context, relations []entity.ResourceRelation) error {
	var clusterIdMap = map[uint64]struct{}{}
	for _, relation := range relations {
		if relation.ResourceType != entity.RoleBindingScopeTiDB.String() {
			tilog.Info(ctx, fmt.Sprintf("id: %d, resource_type is not cluster, ignore", relation.ID))
			continue
		}
		clusterIdMap[relation.ResourceID] = struct{}{}
	}
	var clusterIds []uint64
	for cid := range clusterIdMap {
		clusterIds = append(clusterIds, cid)
	}

	delClusterIds, err := getDeletedClusterIds(ctx, clusterIds)
	if err != nil {
		tilog.Warn(ctx, "get deleted cluster ids error", zap.Any("cluster_ids", clusterIds), zap.Any("err", err))
		return err
	}

	if len(delClusterIds) > 0 {
		for _, cid := range delClusterIds {
			err := rbacsvc.GetResourceRelationSvc().DeleteClusterRelations(ctx, cid)
			tilog.Info(ctx, "system auto delete cluster_org relation and cluster role_binding", zap.Any("cluster_id", cid), zap.Any("err", err))
		}
	}
	return nil
}

func getDeletedClusterIds(ctx context.Context, clusterIds []uint64) ([]uint64, error) {
	if len(clusterIds) == 0 {
		return nil, nil
	}
	clustersRsp, err := mgmt.GeClient().ListClusters(ctx, &mgmtv1.ListClustersRequest{
		Filter: &mgmtv1.ClusterFilter{
			ClusterIds: clusterIds,
		},
	})
	if err != nil {
		return nil, err
	}
	var delClusterIds []uint64
	if clustersRsp != nil && len(clustersRsp.Clusters) > 0 {
		for _, c := range clustersRsp.Clusters {
			if c.DeleteTime != nil {
				delClusterIds = append(delClusterIds, c.ClusterId)
			}
		}
	}
	return delClusterIds, nil
}
