// package resolve provides methods that resolve the TiDB cluster spec from a request
package resolve

import (
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/pingcap/log"
	"go.uber.org/zap"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/client-go/kubernetes"
	v1 "k8s.io/client-go/listers/core/v1"
)

// Cluster represents a TiDB cluster
type Cluster struct {
	Namespace        string
	Name             string
	MonitorName      string
	MonitorNamespace string
}

const (
	sharedTiDBName   = "db"
	sharedTiCDCName  = "db-cdc"
	byIDPrefix       = "/proxy/cluster/"
	cdcServiceFormat = "%s-ticdc-peer"
)

type ByID struct {
	cli       *kubernetes.Clientset
	svcLister v1.ServiceLister
}

func NewByID(cli *kubernetes.Clientset, svcLister v1.ServiceLister) (*ByID, error) {
	return &ByID{
		cli:       cli,
		svcLister: svcLister,
	}, nil
}

func (r *ByID) Prefix() string {
	return byIDPrefix
}

func (r *ByID) Resolve(req *http.Request) (cl Cluster, route string, err error) {
	path := req.URL.Path
	path = strings.TrimPrefix(path, byIDPrefix)
	paths := strings.Split(path, "/")
	if len(paths) <= 1 {
		err = errors.New("empty cluster ID")
		return
	}

	cl.Name = sharedTiDBName
	cl.Namespace = fmt.Sprintf("tidb%s", paths[0])
	if paths[1] == "ticdc" {
		_, err = r.svcLister.Services(cl.Namespace).Get(fmt.Sprintf(cdcServiceFormat, sharedTiDBName))
		if err != nil && !apierrors.IsNotFound(err) {
			log.Warn("Unable to find the tidb cluster db", zap.String("namespace", cl.Namespace))
			return
		} else if err != nil && apierrors.IsNotFound(err) {
			cl.Name = sharedTiCDCName
		}
	}
	cl.MonitorName = sharedTiDBName
	cl.MonitorNamespace = cl.Namespace
	route = strings.Join(paths[1:], "/")
	req.URL.Path = route
	return cl, route, nil
}
