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

import (
	"container/list"
	"strings"
	"sync"
)

import (
	"github.com/apache/dubbo-go/config_center"
)

// Environment
// There is dubbo.properties file and application level config center configuration which higner than normal config center in java. So in java the
// configuration sequence will be config center > application level config center > dubbo.properties > spring bean configuration.
// But in go, neither the dubbo.properties file or application level config center configuration will not support for the time being.
// We just have config center configuration which can override configuration in consumer.yaml & provider.yaml.
// But for add these features in future ,I finish the environment struct following Environment class in java.
type Environment struct {
	configCenterFirst    bool
	externalConfigs      sync.Map
	externalConfigMap    sync.Map
	appExternalConfigMap sync.Map
	dynamicConfiguration config_center.DynamicConfiguration
}

var (
	instance *Environment
	once     sync.Once
)

// GetEnvInstance gets env instance by singleton
func GetEnvInstance() *Environment {
	once.Do(func() {
		instance = &Environment{configCenterFirst: true}
	})
	return instance
}

// NewEnvInstance creates Environment instance
func NewEnvInstance() {
	instance = &Environment{configCenterFirst: true}
}

//func (env *Environment) SetConfigCenterFirst() {
//	env.configCenterFirst = true
//}

//func (env *Environment) ConfigCenterFirst() bool {
//	return env.configCenterFirst
//}

// UpdateExternalConfigMap updates env externalConfigMap field
func (env *Environment) UpdateExternalConfigMap(externalMap map[string]string) {
	for k, v := range externalMap {
		env.externalConfigMap.Store(k, v)
	}
}

// UpdateAppExternalConfigMap updates env appExternalConfigMap field
func (env *Environment) UpdateAppExternalConfigMap(externalMap map[string]string) {
	for k, v := range externalMap {
		env.appExternalConfigMap.Store(k, v)
	}
}

// Configuration puts externalConfigMap and appExternalConfigMap into list
// List represents a doubly linked list.
func (env *Environment) Configuration() *list.List {
	cfgList := list.New()
	// The sequence would be: SystemConfiguration -> ExternalConfiguration -> AppExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
	cfgList.PushFront(newInmemoryConfiguration(&(env.externalConfigMap)))
	cfgList.PushFront(newInmemoryConfiguration(&(env.appExternalConfigMap)))
	return cfgList
}

// SetDynamicConfiguration sets value for dynamicConfiguration
func (env *Environment) SetDynamicConfiguration(dc config_center.DynamicConfiguration) {
	env.dynamicConfiguration = dc
}

// GetDynamicConfiguration gets dynamicConfiguration
func (env *Environment) GetDynamicConfiguration() config_center.DynamicConfiguration {
	return env.dynamicConfiguration
}

// InmemoryConfiguration stores config in memory
type InmemoryConfiguration struct {
	store *sync.Map
}

func newInmemoryConfiguration(p *sync.Map) *InmemoryConfiguration {
	return &InmemoryConfiguration{store: p}
}

// GetProperty gets value from InmemoryConfiguration instance by @key
func (conf *InmemoryConfiguration) GetProperty(key string) (bool, string) {
	if conf.store == nil {
		return false, ""
	}

	v, ok := conf.store.Load(key)
	if ok {
		return true, v.(string)
	}

	return false, ""
}

// GetSubProperty gets sub property from InmemoryConfiguration instance by @subkey
func (conf *InmemoryConfiguration) GetSubProperty(subKey string) map[string]struct{} {
	if conf.store == nil {
		return nil
	}

	properties := make(map[string]struct{})
	conf.store.Range(func(key, _ interface{}) bool {
		if idx := strings.Index(key.(string), subKey); idx >= 0 {
			after := key.(string)[idx+len(subKey):]
			if i := strings.Index(after, "."); i >= 0 {
				properties[after[0:strings.Index(after, ".")]] = struct{}{}
			}

		}
		return true
	})

	return properties
}
