package vm

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/pingcap/log"
	"go.uber.org/zap"

	"github.com/pingcap-inc/clinic/pkg/ngm/topsql/api"
)

const (
	queryTypeInstance = "instance"
)

func (vq *VMQuery) Instances(ctx context.Context, params *api.InstancesParams) ([]api.InstanceItem, error) {
	startSecs := params.StartSecs
	endSecs := params.EndSecs

	if startSecs > endSecs {
		return []api.InstanceItem{}, nil
	}

	addrParams := &addrParams{
		Provider:  params.Provider,
		Region:    params.Region,
		ClusterID: params.ClusterID,
	}
	instanceQuery := fmt.Sprintf(`
present_over_time(topsql_instance{
	provider="%s",
	region="%s",
	cluster_id="%d",
	tenant_id="%d",
	project_id="%d",
}[%ds])
	`,
		params.Provider,
		params.Region,
		params.ClusterID,
		params.TenantID,
		params.ProjectID,
		endSecs-startSecs+1)
	body, err := vq.vmQuery(ctx, queryTypeInstance, instanceQuery, endSecs, addrParams)
	if err != nil {
		log.Warn("failed to fetch instance from vm", zap.Error(err))
		return nil, err
	}

	return extractInstances(body)
}

func extractInstances(body []byte) ([]api.InstanceItem, error) {
	var resp instanceResponse
	if err := json.Unmarshal(body, &resp); err != nil {
		return nil, err
	}

	var res []api.InstanceItem
	for _, result := range resp.Data.Result {
		res = append(res, api.InstanceItem{
			Instance:     result.Metric.Instance,
			InstanceType: result.Metric.InstanceType,
		})
	}

	return res, nil
}

type instanceResponse struct {
	Data instanceResponseData `json:"data"`
}

type instanceResponseData struct {
	Result []instanceResponseResult `json:"result"`
}

type instanceResponseResult struct {
	Metric instanceResponseMetric `json:"metric"`
}

type instanceResponseMetric struct {
	Instance     string `json:"instance"`
	InstanceType string `json:"instance_type"`
}
