package managerserver

import (
	"context"
	"io"
	"net"
	"net/http"
	"time"

	"github.com/pingcap/errors"
	"github.com/tidbcloud/aws-shared-provider/pkg/metrics"
	"github.com/tidbcloud/aws-shared-provider/pkg/utils"
	"github.com/tidbcloud/aws-shared-provider/pkg/utils/tidb"
	clientv3 "go.etcd.io/etcd/client/v3"
)

const (
	retryTimes = 4
)

func (s *server) checkconn(w http.ResponseWriter, r *http.Request) {
	logger := log.WithName("tidb/checkconn")
	logger.V(1).Info("req param", "req", r.URL)

	var err error
	var token, connID, ip string
	start := time.Now()

	defer func() {
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			_, _ = io.WriteString(w, err.Error())
			metrics.RequestHistogram.WithLabelValues("checkconn", "500", "").Observe(time.Since(start).Seconds())
			return
		}
		metrics.RequestHistogram.WithLabelValues("checkconn", "200", "").Observe(time.Since(start).Seconds())
	}()

	token, connID, ip = r.URL.Query().Get("token"), r.URL.Query().Get("conn_id"), r.URL.Query().Get("ip")
	if token == "" || connID == "" || ip == "" {
		emptyParamErr := errors.New("token or conn_id or ip empty")
		logger.Error(emptyParamErr, "get param")
		err = emptyParamErr
		return
	}

	logger = logger.WithValues("token", token, "conn_id", connID, "ip", ip)

	for i := 0; i < retryTimes; i++ {
		var tidbResp []byte
		ctx2s, cancel2s := context.WithTimeout(r.Context(), 2*time.Second) //nolint:mnd // no need
		tidbResp, err = s.tidbController.CheckConn(ctx2s, net.JoinHostPort(ip, "10080"), utils.TrimToken(token), connID)
		cancel2s()
		if err != nil {
			logger.Error(err, "tidb CheckConn failed", "retryTimes", i)
		} else {
			logger.Info("CheckConn result", "tidbResp", string(tidbResp), "retryTimes", i)
			if string(tidbResp) == tidb.ConnNormalClosed {
				_, _ = io.WriteString(w, tidb.ConnNormalClosed)
				return
			}
		}

		logger.Info("still need check from etcd", "retryTimes", i)

		var etcdResp *clientv3.GetResponse
		if etcdResp, err = s.etcdKV.Get(r.Context(), s.etcdCheckConnPrefix+token+"-"+ip); err != nil {
			logger.Error(err, "failed to get normal restart log from etcd", "retryTimes", i)
			return
		}
		if len(etcdResp.Kvs) > 0 {
			logger.Info("found normal restart log from etcd, its normal closed",
				"msg", string(etcdResp.Kvs[0].Value), "retryTimes", i)
			_, _ = io.WriteString(w, tidb.ConnNormalClosed)
			return
		}

		if i < retryTimes-1 {
			time.Sleep(2 * time.Second) //nolint:mnd // no need
		}
	}
	logger.Info("connection is unconfirmed")
	_, _ = io.WriteString(w, "unconfirmed")
}
