// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package volumebestfit

import (
	"sort"

	"github.com/pingcap/tidb-operator/pkg/scheduler/predicates"
	"github.com/pingcap/tidb-operator/pkg/scheduler/volume"
	apiv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
)

type volumeBestFit struct {
	weight int32
}

// NewVolumeBestFit returns a predicates.Predicate
func NewVolumeBestFit(weight int32) predicates.Predicate {
	return &volumeBestFit{weight}
}

// Name returns the predicate name
func (vbf *volumeBestFit) Name() string {
	return "VolumeBestFit"
}

// Filter tries to find a best fit volume which capacity is the lowest
func (vbf *volumeBestFit) Filter(tidbVol *volume.TiDBVolume, pod *apiv1.Pod, pvc *apiv1.PersistentVolumeClaim) (bool, error) {
	sort.Slice(tidbVol.Volumes, func(i, j int) bool {
		return tidbVol.Volumes[i].Size.Cmp(tidbVol.Volumes[j].Size) == -1
	})

	var latestQuantityLevel resource.Quantity
	latestPriorityLevel := int32(1)

	for idx := len(tidbVol.Volumes) - 1; idx >= 0; idx-- {
		vol := &tidbVol.Volumes[idx]
		if idx == len(tidbVol.Volumes)-1 {
			latestQuantityLevel = vol.Size
		}

		if vol.Size.Cmp(latestQuantityLevel) != 0 {
			latestQuantityLevel = vol.Size
			latestPriorityLevel++
		}

		vol.Priority += latestPriorityLevel * vbf.weight
	}

	return false, nil
}
