package cluster

import (
	"context"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	configbackuprepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/configbackup"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

const (
	defaultListClusterConfigBackupPage     = int64(1)
	defaultListClusterConfigBackupPageSize = int64(20)
	maxListClusterConfigBackupPageSize     = int64(100)
)

var listClusterConfigBackupSortableColumns = map[string]string{
	"last_backup_at":  "last_backup_at",
	"last_success_at": "last_success_at",
	"interval_sec":    "interval_sec",
	"created_at":      "created_at",
	"updated_at":      "updated_at",
	"cluster_id":      "cluster_id",
}

func (s *serviceImpl) ListClusterConfigBackup(
	ctx context.Context,
	req *globaldedicatedv1.ListClusterConfigBackupRequest,
) (*globaldedicatedv1.ListClusterConfigBackupResponse, bizerr.BizError) {
	option, err := buildPolicyQueryOption(req)
	if err != nil {
		return nil, err
	}

	items, total, err := s.configBackupPolicyRepo.Query(ctx, option)
	if err != nil {
		return nil, err
	}

	resp := &globaldedicatedv1.ListClusterConfigBackupResponse{
		Items: make([]*globaldedicatedv1.ClusterConfigBackupPolicy, 0, len(items)),
		Total: total,
	}
	for _, item := range items {
		resp.Items = append(resp.Items, toClusterConfigBackupPolicyProto(item))
	}

	return resp, nil
}

func buildPolicyQueryOption(
	req *globaldedicatedv1.ListClusterConfigBackupRequest,
) (*configbackuprepo.PolicyQueryOption, bizerr.BizError) {
	page := defaultListClusterConfigBackupPage
	pageSize := defaultListClusterConfigBackupPageSize
	if req.GetPager() != nil {
		if req.GetPager().GetPage() > 0 {
			page = req.GetPager().GetPage()
		}
		if req.GetPager().GetPageSize() > 0 {
			pageSize = req.GetPager().GetPageSize()
		}
	}
	if pageSize > maxListClusterConfigBackupPageSize {
		pageSize = maxListClusterConfigBackupPageSize
	}

	option := &configbackuprepo.PolicyQueryOption{
		Page:     page,
		PageSize: pageSize,
		Filter:   buildPolicyQueryFilter(req.GetFilter()),
	}
	sorters, err := buildPolicyQuerySorters(req.GetSorters())
	if err != nil {
		return nil, err
	}
	option.Sorters = sorters

	return option, nil
}

func buildPolicyQueryFilter(
	filter *globaldedicatedv1.ListClusterConfigBackupRequest_ClusterConfigBackupFilter,
) *configbackuprepo.PolicyQueryFilter {
	if filter == nil {
		return nil
	}

	out := &configbackuprepo.PolicyQueryFilter{
		ClusterIDs: filter.GetClusterIds(),
	}

	if filter.Enabled != nil {
		out.Enabled = filter.Enabled
	}
	if filter.HasError != nil {
		out.HasError = filter.HasError
	}
	if filter.GetLastBackupAtFrom() != nil {
		t := filter.GetLastBackupAtFrom().AsTime()
		out.LastBackupAtFrom = &t
	}
	if filter.GetLastBackupAtTo() != nil {
		t := filter.GetLastBackupAtTo().AsTime()
		out.LastBackupAtTo = &t
	}
	if filter.GetLastSuccessAtFrom() != nil {
		t := filter.GetLastSuccessAtFrom().AsTime()
		out.LastSuccessAtFrom = &t
	}
	if filter.GetLastSuccessAtTo() != nil {
		t := filter.GetLastSuccessAtTo().AsTime()
		out.LastSuccessAtTo = &t
	}

	return out
}

func buildPolicyQuerySorters(
	sorters []*globaldedicatedv1.Sorter,
) ([]configbackuprepo.PolicyQuerySorter, bizerr.BizError) {
	if len(sorters) == 0 {
		return []configbackuprepo.PolicyQuerySorter{
			{OrderBy: "last_backup_at", Desc: true},
			{OrderBy: "cluster_id", Desc: false},
		}, nil
	}

	out := make([]configbackuprepo.PolicyQuerySorter, 0, len(sorters))
	for _, sorter := range sorters {
		column, ok := listClusterConfigBackupSortableColumns[sorter.GetOrderBy()]
		if !ok {
			return nil, bizerr.New(bizerr.ErrCodeParams, "unsupported sorter order_by: %s", sorter.GetOrderBy())
		}
		out = append(out, configbackuprepo.PolicyQuerySorter{
			OrderBy: column,
			Desc:    sorter.GetSort() == globaldedicatedv1.Sorter_DESC,
		})
	}

	return out, nil
}
