package controller

import (
	"errors"
	"fmt"
	"os"

	"github.com/pingcap/log"
	"github.com/pingcap/tidb-operator/pkg/label"
	"go.uber.org/zap"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	TiDBSvcPortName = "mysql-client"
	TEPNameLabelVal = "tep-server"
)

func GetTiDBSvcDNSName(namespace string) string {
	return fmt.Sprintf("%s-tidb.%s.svc", namespace, namespace)
}

// GetTiDBEndpoints returns the endpoints that you could access tidb cluster
func (c *Controller) GetTiDBEndpoints(namespace, serviceName string) (addrs []string, port int32, err error) {
	addrs = []string{}
	tidbSvc, err := c.kubeCli.CoreV1().Services(namespace).Get(serviceName, metav1.GetOptions{})
	if err != nil {
		log.Error("failed to query service", zap.String("namespace", namespace), zap.String("service", serviceName), zap.Error(err))
		return addrs, 0, err
	}

	tidbSvcPorts := tidbSvc.Spec.Ports
	// TODO: add other Service Type, by default TiDB service is exposed using NodePort
	if tidbSvc.Spec.Type == corev1.ServiceTypeNodePort {
		for _, svcPort := range tidbSvcPorts {
			if svcPort.Name == TiDBSvcPortName {
				port = svcPort.NodePort
			}
		}
		podList, err := c.kubeCli.CoreV1().Pods(namespace).List(metav1.ListOptions{
			LabelSelector: fmt.Sprintf("%s=%s", label.ComponentLabelKey, label.TiDBLabelVal),
		})
		if err != nil {
			log.Error("failed to query tidb pod", zap.String("namespace", namespace), zap.Error(err))
			return addrs, 0, err
		}
		for _, pod := range podList.Items {
			if pod.Status.Phase == corev1.PodRunning {
				addrs = append(addrs, pod.Status.HostIP)
			}
		}
		return addrs, port, nil
	}

	return
}

// getMonitorServiceEndpoint returns the endpoint of K8s monitor service from outside the cluster
func (c *Controller) getMonitorServiceEndpoint(namespace, serviceName string) (addr string, err error) {
	service, err := c.kubeCli.CoreV1().Services(namespace).Get(serviceName, metav1.GetOptions{})
	if err != nil {
		log.Error("failed to query service", zap.String("namespace", namespace), zap.String("service", serviceName), zap.Error(err))
		return
	}

	if service.Spec.Type != corev1.ServiceTypeNodePort {
		err = fmt.Errorf("the type of service[%s] in namespace[%s] is not NodePort", serviceName, namespace)
		return
	}

	port := service.Spec.Ports[0].NodePort

	ns := os.Getenv("NAMESPACE")
	if ns == "" {
		err = errors.New("NAMESPACE environment variable not set")
		return
	}
	podList, err := c.kubeCli.CoreV1().Pods(ns).List(metav1.ListOptions{
		LabelSelector: fmt.Sprintf("%s=%s", label.NameLabelKey, TEPNameLabelVal),
	})
	if err != nil {
		log.Error("failed to query tep-server pod", zap.String("namespace", namespace), zap.Error(err))
		return
	}

	for _, pod := range podList.Items {
		if pod.Status.Phase == corev1.PodRunning {
			addr = fmt.Sprintf("http://%s:%d", pod.Status.HostIP, port)
			return
		}
	}

	err = errors.New("unable to get endpoint of service[%s] in namespace[%s]")
	return
}
