/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package etcdv3

import (
	gxetcd "github.com/dubbogo/gost/database/kv/etcd/v3"
	"github.com/dubbogo/gost/log/logger"

	perrors "github.com/pkg/errors"
)

// ValidateClient validates client and sets options
func ValidateClient(container clientFacade, opts ...gxetcd.Option) error {
	options := &gxetcd.Options{}
	for _, opt := range opts {
		opt(options)
	}
	lock := container.ClientLock()
	lock.Lock()
	defer lock.Unlock()

	// new Client
	if container.Client() == nil {
		newClient, err := gxetcd.NewClient(options.Name, options.Endpoints, options.Timeout, options.Heartbeat)
		if err != nil {
			logger.Warnf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%s}) = error{%v}",
				options.Name, options.Endpoints, options.Timeout.String(), err)
			return perrors.WithMessagef(err, "new client (address:%+v)", options.Endpoints)
		}
		container.SetClient(newClient)
	}

	// Client lose connection with etcd server
	if container.Client().GetRawClient() == nil {
		newClient, err := gxetcd.NewClient(options.Name, options.Endpoints, options.Timeout, options.Heartbeat)
		if err != nil {
			logger.Warnf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%s}) = error{%v}",
				options.Name, options.Endpoints, options.Timeout.String(), err)
			return perrors.WithMessagef(err, "new client (address:%+v)", options.Endpoints)
		}
		container.SetClient(newClient)
	}

	return nil
}

// NewServiceDiscoveryClient creates a new etcd client for service discovery with sensible defaults.
func NewServiceDiscoveryClient(opts ...gxetcd.Option) *gxetcd.Client {
	options := &gxetcd.Options{
		Heartbeat: 1, // default heartbeat
	}
	for _, opt := range opts {
		opt(options)
	}

	newClient, err := gxetcd.NewClient(options.Name, options.Endpoints, options.Timeout, options.Heartbeat)
	if err != nil {
		logger.Errorf("new etcd client (name{%s}, etcd addresses{%v}, timeout{%s}) = error{%v}",
			options.Name, options.Endpoints, options.Timeout.String(), err)
	}
	return newClient
}
