package server

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"slices"
	"time"

	"github.com/pingcap/log"
	dto "github.com/prometheus/client_model/go"
	"github.com/tidbcloud/serverless-metering/pkg/config"
	"go.uber.org/zap"
)

var rcuMetricNames = []string{
	"resource_manager_resource_unit_read_request_unit_sum",
	"resource_manager_resource_unit_write_request_unit_sum",
	"resource_manager_resource_unit_sql_layer_request_unit",
	"resource_manager_resource_unit_sql_layer_request_unit_sum",
	"resource_manager_resource_unit_request_unit_v2_sum",
}

type metricForwarder struct {
	rcuClient *http.Client
	rcuHost   string
	rcuPort   int
}

func newMetricForwarder() *metricForwarder {
	cfg := config.Global().Server
	return &metricForwarder{
		rcuClient: &http.Client{
			Timeout: time.Second * 10,
		},
		rcuHost: cfg.RcuHost,
		rcuPort: cfg.RcuPort,
	}
}

func (f *metricForwarder) forwardMetrics(metricFamilies map[string]*dto.MetricFamily) {
	for name, mf := range metricFamilies {
		if slices.Contains(rcuMetricNames, name) {
			// TODO: control the number of goroutines if needed
			go f.forwardMetricFamily(mf)
		}
	}
}

func (f *metricForwarder) forwardMetricFamily(mf *dto.MetricFamily) {
	jsonData, err := json.Marshal(mf)
	if err != nil {
		log.Error("failed to marshal metric family", zap.String("name", mf.GetName()), zap.Error(err))
		return
	}
	resp, err := f.rcuClient.Post(fmt.Sprintf("http://%s:%d/api/v1/rcu/metrics", f.rcuHost, f.rcuPort), "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Error("failed to forward metric family", zap.String("name", mf.GetName()), zap.Error(err))
		return
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Error("failed to read response for metric family", zap.String("name", mf.GetName()), zap.Error(err))
		return
	}
	if resp.StatusCode != http.StatusOK {
		log.Error("failed to forward metric family", zap.Int("status", resp.StatusCode), zap.String("name", mf.GetName()), zap.String("body", string(body)))
		return
	}
}
