package managerserver

import (
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"

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

const (
	checkConnKeyTTLSeconds = 90
)

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

	var err error
	var podName, podIP, ns, normalRestartLog string
	start := time.Now()

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

	podName = r.URL.Query().Get("pod_name")
	podIP = r.URL.Query().Get("pod_ip")
	ns = r.URL.Query().Get("ns")
	normalRestartLog = r.URL.Query().Get("normal_restart_log")
	if podName == "" || podIP == "" {
		noPodErr := errors.New("no pod name or ip")
		logger.Error(noPodErr, "get pod")
		err = noPodErr
		return
	}

	logger = logger.WithValues("pod name", podName, "pod ip", podIP, "ns", ns)

	var token, msg string
	activeSecondsValue := r.URL.Query().Get("active_seconds")
	activeSeconds, hasActiveSeconds := parseTiDBActiveSeconds(activeSecondsValue)
	if activeSecondsValue != "" && !hasActiveSeconds {
		logger.Info("ignore invalid tidb active duration", "active_seconds", activeSecondsValue)
	}
	if normalRestartLog != "" {
		logger.Info("normal restart log: " + normalRestartLog)
		//nolint:mnd // no need
		if parts := strings.SplitN(normalRestartLog, ":", 2); len(parts) < 2 {
			logger.Error(nil, "invalid tidb normal restart log file")
		} else {
			token, msg = parts[0], parts[1]
			// Grant a lease with a TTL
			lease, err := s.etcdLease.Grant(s.ctx, checkConnKeyTTLSeconds)
			if err != nil {
				logger.Error(err, "failed to grant a lease")
			} else {
				_, err = s.etcdKV.Put(s.ctx, s.etcdCheckConnPrefix+token+"-"+podIP, msg, clientv3.WithLease(lease.ID))
				if err != nil {
					logger.Error(err, "failed to put normal restart log to etcd")
				}
			}
		}
	}

	tManager := s.tManagers[ns]
	if tManager == nil {
		logger.Error(noTidbPoolErr, "noTidbPoolErr")
		err = noTidbPoolErr
		return
	}
	if hasActiveSeconds {
		metrics.TiDBActiveDurationHistogram.WithLabelValues(ns).Observe(activeSeconds)
	}

	go func() {
		if err := tManager.FreeTidb(s.ctx, podName, podIP, msg); err != nil {
			logger.Error(err, "freeTidb")
			return
		}
	}()
}

func parseTiDBActiveSeconds(value string) (float64, bool) {
	if value == "" {
		return 0, false
	}
	seconds, err := strconv.ParseUint(value, 10, 64)
	if err != nil {
		return 0, false
	}
	return float64(seconds), true
}
