// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.package spec

package controller

import (
	"reflect"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/tidb-operator/pkg/apis/pingcap.com/v1"
	"github.com/pingcap/tidb-operator/pkg/util"
	"github.com/pingcap/tidb-operator/pkg/util/label"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func (tcc *TiDBClusterController) syncConfigMapFor(cluster *v1.TidbCluster) error {
	ns := cluster.GetNamespace()
	if cluster.Spec.ConfigMap != "" {
		log.Debugf("use the specified configmap %s/%s instead of managing a configmap", ns, cluster.Spec.ConfigMap)
		return nil
	}

	// following syncing logic is reserved for backward compatible
	// so old tidb-cloud-manager can work with new tidb-operator
	name := cluster.GetConfigMapName()

	cm, err := tcc.kubeCli.CoreV1().ConfigMaps(ns).Get(name, metav1.GetOptions{})
	if err != nil {
		if apierrors.IsNotFound(err) {
			return tcc.createConfigMapFor(cluster)
		}

		return errors.Trace(err)
	}

	if cm.Annotations == nil {
		cm.Annotations = make(map[string]string)
	}

	newAnno := util.AnnPaused(nil, cluster)
	if cm.Annotations[label.AnnPaused] == newAnno[label.AnnPaused] && reflect.DeepEqual(cluster.Spec.Config, cm.Data) {
		return nil
	}

	cm.Annotations[label.AnnPaused] = newAnno[label.AnnPaused]
	cm.Data = cluster.Spec.Config

	_, err = tcc.kubeCli.CoreV1().ConfigMaps(ns).Update(cm)
	if err != nil {
		log.Errorf("ConfigMap[%s/%s] updated failed: %v", ns, name, err)
		return errors.Trace(err)
	}

	log.Infof("ConfigMap[%s/%s] updated successfully.", ns, name)
	return nil
}

func (tcc *TiDBClusterController) createConfigMapFor(cluster *v1.TidbCluster) error {
	clusterName := cluster.GetName()
	ns := cluster.GetNamespace()
	name := cluster.GetConfigMapName()

	if cluster.Spec.Config == nil {
		log.Warnf("cluster: %s/%s, no config provided, use default", ns, clusterName)
		return nil
	}

	cm := &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:            name,
			Namespace:       ns,
			Labels:          label.New().Cluster(clusterName).App("config").Labels(),
			OwnerReferences: []metav1.OwnerReference{getOwnerRef(cluster)},
			Annotations:     util.AnnPaused(nil, cluster),
		},
		Data: cluster.Spec.Config,
	}

	_, err := tcc.kubeCli.CoreV1().ConfigMaps(ns).Create(cm)
	if err != nil {
		log.Errorf("ConfigMap[%s/%s] created failed: %v", ns, name, err)
		return errors.Trace(err)
	}

	log.Infof("ConfigMap[%s/%s] created successfully", ns, name)
	return nil
}
