package mysql

import (
	"context"
	"fmt"
	"strings"
	"sync"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/schrodinger/pkg/types"
	"github.com/pingcap/schrodinger/util"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

const (
	nodeLabel = "node"
)

// SQLClient manages mysql
type SQLClient struct {
	sync.RWMutex
	k8sCli kubernetes.Interface
}

// NewMysqlClient returns a SQLClient that manages tidb cluster on k8s
func NewMysqlClient(k8sCli kubernetes.Interface) *SQLClient {
	return &SQLClient{
		k8sCli: k8sCli,
	}
}

// CreateAPP creates app
func (c *SQLClient) CreateAPP(ctx context.Context, app *types.APPConfig) error {
	c.Lock()
	defer c.Unlock()

	err := c.checkOrCreateNamespace(app.Namespace)
	if err != nil {
		return errors.Trace(err)
	}

	if err = c.createDBPod(ctx, app); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (c *SQLClient) checkOrCreateNamespace(namespace string) error {
	isExist, err := util.CheckNamespaceIsExist(namespace, c.k8sCli)
	if err != nil {
		return errors.Trace(err)
	}
	if !isExist {
		err = util.CreateK8sNamespace(namespace, c.k8sCli)
		if err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

func (c *SQLClient) createDBPod(ctx context.Context, app *types.APPConfig) error {
	containers := []v1.Container{
		{
			Name:  util.FormatSnakeCase(app.Name),
			Image: getImage(app),
			Env: []v1.EnvVar{
				{
					Name:  "MYSQL_ROOT_HOST",
					Value: "%",
				},
				{
					Name:  "MYSQL_ALLOW_EMPTY_PASSWORD",
					Value: "true",
				},
			},
			Ports: []v1.ContainerPort{
				{
					ContainerPort: app.Port,
				},
			},
			VolumeMounts: []v1.VolumeMount{
				{
					Name:      "myconf",
					ReadOnly:  false,
					MountPath: "/etc/mysql",
				},
				{
					Name:      "timezone",
					ReadOnly:  true,
					MountPath: "/etc/localtime",
				},
			},
		},
	}

	meta := metav1.ObjectMeta{
		Name: util.FormatSnakeCase(app.Name),
	}

	pod, err := util.CreatePod(app.Namespace, c.k8sCli, &v1.Pod{
		ObjectMeta: meta,
		Spec: v1.PodSpec{
			InitContainers: []v1.Container{
				{
					Name:  "init-mysql",
					Image: "busybox:1.26.2",
					Command: []string{"sh", "-c",
						fmt.Sprintf("mkdir -p /etc/mysql/conf.d && wget --tries 20 -O /etc/mysql/my.cnf %s",
							getConfDownloadURL(app))},
					VolumeMounts: []v1.VolumeMount{
						{
							Name:      "myconf",
							ReadOnly:  false,
							MountPath: "/etc/mysql",
						},
					},
				},
			},
			Containers: containers,
			Volumes: []v1.Volume{
				{
					Name:         "myconf",
					VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}},
				},
				{
					Name:         "timezone",
					VolumeSource: v1.VolumeSource{HostPath: &v1.HostPathVolumeSource{Path: "/etc/localtime"}},
				},
			},
			NodeSelector: util.GetLabels(app.Labels, nodeLabel),
		},
	})

	if err != nil && !strings.Contains(err.Error(), "already exists") {
		return errors.Trace(err)
	}

	if ok := util.CheckPodIsRunning(ctx, app.Namespace, app.Name, c.k8sCli); !ok {
		return errors.Errorf("Create pod %s failed", app.Name)
	}

	pod, err = util.GetPod(app.Namespace, app.Name, c.k8sCli)
	if err != nil {
		return errors.Trace(err)
	}

	app.Host = pod.Status.PodIP
	for _, c := range pod.Status.ContainerStatuses {
		app.ContainerIDs = append(app.ContainerIDs, c.ContainerID)
	}

	log.Debugf("db addr:%s", app.Host)

	return nil
}
