package vm

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

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

	"github.com/tidbcloud/observability/o11ydiagnosis/pkg/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{
		Env:         params.Env,
		TenantID:    fmt.Sprintf("%d", params.TenantID),
		ClusterID:   fmt.Sprintf("%d", params.ClusterID),
		NextGen:     params.NextGen,
		NextGenHost: params.NextGenHost,
		Byoc:        params.Byoc,
	}
	instanceQuery := fmt.Sprintf(`present_over_time(topsql_instance{cluster_id="%d"}[%ds])`, params.ClusterID, endSecs-startSecs+1)
	if params.NextGenHost {
		instanceQuery = fmt.Sprintf(`present_over_time(topsql_instance{sharedpool_id="%d"}[%ds])`, params.ClusterID, 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 = make([]api.InstanceItem, 0, len(resp.Data.Result))
	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"`
}
