/*
 * 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 registry

import (
	"net/url"
	"strconv"
	"strings"
)

import (
	"github.com/apache/dubbo-go/common"
	"github.com/apache/dubbo-go/common/constant"
	consul "github.com/hashicorp/consul/api"
	perrors "github.com/pkg/errors"
)

import (
	"github.com/apache/dubbo-go-pixiu/pkg/logger"
)

func init() {
	var _ Loader = new(ConsulRegistryLoad)
}

const (
	dubboAPIFilter = "dubbo in Tags"
)

// ConsulRegistryLoad load dubbo apis from consul registry
type ConsulRegistryLoad struct {
	Address string
	// Consul client.
	client  *consul.Client
	cluster string
}

func newConsulRegistryLoad(address, cluster string) (Loader, error) {
	config := &consul.Config{Address: address}
	client, err := consul.NewClient(config)
	if err != nil {
		return nil, err
	}

	r := &ConsulRegistryLoad{
		Address: address,
		client:  client,
		cluster: cluster,
	}

	return r, nil
}

// nolint
func (crl *ConsulRegistryLoad) GetCluster() (string, error) {
	return crl.cluster, nil
}

func (crl *ConsulRegistryLoad) transfer2Url(service consul.AgentService) (*common.URL, error) {
	params := url.Values{}
	var protocol string

	for _, tag := range service.Tags {
		kv := strings.Split(tag, "=")
		if len(kv) != 2 {
			continue
		}
		params.Add(kv[0], kv[1])
	}

	if url, ok := service.Meta["url"]; ok {
		protocol = strings.Split(url, ":")[0]
	}

	methodsParam := strings.Split(params.Get(constant.METHODS_KEY), ",")
	methods := make([]string, len(methodsParam))
	for _, method := range methodsParam {
		if method != "" {
			methods = append(methods, method)
		}
	}
	url := common.NewURLWithOptions(common.WithPort(strconv.Itoa(service.Port)),
		common.WithProtocol(protocol), common.WithMethods(methods),
		common.WithIp(service.Address), common.WithParams(params))

	return url, nil
}

// LoadAllServices load all services from consul registry
func (crl *ConsulRegistryLoad) LoadAllServices() ([]*common.URL, error) {
	agentServices, err := crl.client.Agent().ServicesWithFilter(dubboAPIFilter)
	if err != nil {
		logger.Error("consul load all apis error:%v", err)
		return nil, perrors.Wrap(err, "consul load all apis")
	}
	var urls []*common.URL
	for _, service := range agentServices {
		url, err := crl.transfer2Url(*service)
		if err != nil {
			logger.Warnf("consul transfer service to url error:%v", err)
			continue
		}
		urls = append(urls, url)
	}
	return urls, nil
}
