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

import (
	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/vo"

	"github.com/pkg/errors"
)

import (
	"github.com/apache/dubbo-go-pixiu/pkg/adapter/dubboregistry/common"
	"github.com/apache/dubbo-go-pixiu/pkg/adapter/dubboregistry/registry"
	baseRegistry "github.com/apache/dubbo-go-pixiu/pkg/adapter/dubboregistry/registry/base"
	"github.com/apache/dubbo-go-pixiu/pkg/common/constant"
	"github.com/apache/dubbo-go-pixiu/pkg/common/util/stringutil"
	"github.com/apache/dubbo-go-pixiu/pkg/model"
)

func init() {
	registry.SetRegistry(constant.Nacos, newNacosRegistry)
}

type NacosRegistry struct {
	*baseRegistry.BaseRegistry
	nacosListeners map[registry.RegisteredType]registry.Listener
	client         naming_client.INamingClient
}

func (n *NacosRegistry) DoSubscribe() error {
	Listener, ok := n.nacosListeners[n.RegisteredType]
	if !ok {
		return errors.New("Listener for interface level registration does not initialized")
	}
	go Listener.WatchAndHandle()
	return nil
}

func (n *NacosRegistry) DoUnsubscribe() error {
	panic("implement me")
}

var _ registry.Registry = new(NacosRegistry)

func newNacosRegistry(regConfig model.Registry, adapterListener common.RegistryEventListener) (registry.Registry, error) {
	addrs, err := stringutil.GetIPAndPort(regConfig.Address)
	if err != nil {
		return nil, err
	}

	scs := make([]nacosConstant.ServerConfig, 0)
	for _, addr := range addrs {
		scs = append(scs, nacosConstant.ServerConfig{
			IpAddr: addr.IP.String(),
			Port:   uint64(addr.Port),
		})
	}

	ccs := nacosConstant.NewClientConfig(
		nacosConstant.WithNamespaceId(regConfig.Namespace),
		nacosConstant.WithUsername(regConfig.Username),
		nacosConstant.WithPassword(regConfig.Password),
		nacosConstant.WithNotLoadCacheAtStart(true),
		nacosConstant.WithUpdateCacheWhenEmpty(true))
	client, err := clients.NewNamingClient(vo.NacosClientParam{
		ServerConfigs: scs,
		ClientConfig:  ccs,
	})
	if err != nil {
		return nil, err
	}

	nacosRegistry := &NacosRegistry{
		client:         client,
		nacosListeners: make(map[registry.RegisteredType]registry.Listener),
	}
	nacosRegistry.BaseRegistry = baseRegistry.NewBaseRegistry(nacosRegistry, adapterListener, registry.RegisterTypeFromName(regConfig.RegistryType))
	switch nacosRegistry.RegisteredType {
	case registry.RegisteredTypeInterface:
		nacosRegistry.nacosListeners[nacosRegistry.RegisteredType] = newNacosIntfListener(client, nacosRegistry, &regConfig, adapterListener)
	case registry.RegisteredTypeApplication:
		nacosRegistry.nacosListeners[nacosRegistry.RegisteredType] = newNacosAppListener(client, nacosRegistry, &regConfig, adapterListener)
	default:
		return nil, errors.Errorf("Unsupported registry type: %s", regConfig.RegistryType)
	}
	return nacosRegistry, nil
}
