// Copyright 2019 Yunion
//
// 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package balancer

import (
	"context"

	"yunion.io/x/jsonutils"
	"yunion.io/x/pkg/errors"

	api "yunion.io/x/onecloud/pkg/apis/monitor"
	"yunion.io/x/onecloud/pkg/mcclient/modules/monitor"
	"yunion.io/x/onecloud/pkg/monitor/tsdb"
)

type HostMetric struct {
	Id     string
	Values map[string]float64
}

type HostMetrics struct {
	metrics []*HostMetric
	indexes map[string]*HostMetric
}

func NewHostMetrics(ms []*HostMetric) *HostMetrics {
	h := &HostMetrics{
		metrics: ms,
		indexes: make(map[string]*HostMetric),
	}
	for _, m := range ms {
		h.indexes[m.Id] = m
	}
	return h
}

func (hs HostMetrics) JSONString() string {
	return jsonutils.Marshal(hs.metrics).String()
}

func (hs HostMetrics) Get(id string) *HostMetric {
	return hs.indexes[id]
}

type TsdbQuery struct {
	Database    string
	Measurement string
	Fields      []string
}

func InfluxdbQuery(
	ds *tsdb.DataSource,
	idKey string,
	hosts []IResource,
	query *TsdbQuery) (*HostMetrics, error) {
	q := monitor.NewAlertQuery(query.Database, query.Measurement).From("5m").To("now")
	sels := q.Selects()
	for _, field := range query.Fields {
		sels.Select(field).MEAN().AS(field)
	}
	ids := []string{}
	for _, h := range hosts {
		ids = append(ids, h.GetId())
	}
	q.Where().IN(idKey, ids)
	q.GroupBy().TAG(idKey).FILL_NULL()
	qCtx := q.ToTsdbQuery()

	resp, err := tsdb.HandleRequest(context.Background(), ds, qCtx)
	if err != nil {
		return nil, errors.Wrap(err, "TSDB endpoint Query")
	}

	ss := resp.Results[""].Series
	ms := make([]*HostMetric, len(ss))
	for i, s := range ss {
		m := &HostMetric{
			Id:     s.Tags[idKey],
			Values: make(map[string]float64),
		}
		for j, f := range query.Fields {
			m.Values[f] = *(s.Points[0][j].(*float64))
		}
		ms[i] = m
	}
	return NewHostMetrics(ms), nil
}

func GetAlertSettingThreshold(s *api.AlertSetting) (float64, error) {
	if len(s.Conditions) != 1 {
		return 0, errors.Errorf("AlertSetting conditions %d != 1", len(s.Conditions))
	}
	return s.Conditions[0].Evaluator.Params[0], nil
}