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

import (
	"fmt"
	"hash/crc32"
	"net/url"
	"sort"
	"strings"
)

import (
	gxset "github.com/dubbogo/gost/container/set"
)

import (
	"dubbo.apache.org/dubbo-go/v3/common/constant"
)

var IncludeKeys = gxset.NewSet(
	constant.APPLICATION_KEY,
	constant.GROUP_KEY,
	constant.TIMESTAMP_KEY,
	constant.SERIALIZATION_KEY,
	constant.CLUSTER_KEY,
	constant.LOADBALANCE_KEY,
	constant.PATH_KEY,
	constant.TIMEOUT_KEY,
	constant.TOKEN_KEY,
	constant.VERSION_KEY,
	constant.WARMUP_KEY,
	constant.WEIGHT_KEY,
	constant.RELEASE_KEY)

// MetadataInfo the metadata information of instance
type MetadataInfo struct {
	Reported bool                    `json:"-"`
	App      string                  `json:"app,omitempty"`
	Revision string                  `json:"revision,omitempty"`
	Services map[string]*ServiceInfo `json:"services,omitempty"`
}

// nolint
func NewMetadataInfWithApp(app string) *MetadataInfo {
	return NewMetadataInfo(app, "", make(map[string]*ServiceInfo))
}

// nolint
func NewMetadataInfo(app string, revision string, services map[string]*ServiceInfo) *MetadataInfo {
	return &MetadataInfo{
		App:      app,
		Revision: revision,
		Services: services,
		Reported: false,
	}
}

// nolint
func (mi *MetadataInfo) JavaClassName() string {
	return "org.apache.dubbo.metadata.MetadataInfo"
}

// CalAndGetRevision is different from Dubbo because golang doesn't support overload
// so that we should use interface + method name as identifier and ignore the method params
// in my opinion, it's enough because Dubbo actually ignore the URL params.
// please refer org.apache.dubbo.common.URL#toParameterString(java.lang.String...)
func (mi *MetadataInfo) CalAndGetRevision() string {
	if mi.Revision != "" && mi.Reported {
		return mi.Revision
	}
	if len(mi.Services) == 0 {
		return "0"
	}
	candidates := make([]string, 8)

	for _, s := range mi.Services {
		sk := s.ServiceKey
		ms := s.URL.Methods
		if len(ms) == 0 {
			candidates = append(candidates, sk)
		} else {
			for _, m := range ms {
				// methods are part of candidates
				candidates = append(candidates, sk+constant.KEY_SEPARATOR+m)
			}
		}

		// append URL params if we need it
	}
	sort.Strings(candidates)

	// it's nearly impossible to be overflow
	res := uint64(0)
	for _, c := range candidates {
		res += uint64(crc32.ChecksumIEEE([]byte(c)))
	}
	mi.Revision = fmt.Sprint(res)
	return mi.Revision

}

// nolint
func (mi *MetadataInfo) HasReported() bool {
	return mi.Reported
}

// nolint
func (mi *MetadataInfo) MarkReported() {
	mi.Reported = true
}

// nolint
func (mi *MetadataInfo) AddService(service *ServiceInfo) {
	if service == nil {
		return
	}
	mi.Services[service.GetMatchKey()] = service
}

// nolint
func (mi *MetadataInfo) RemoveService(service *ServiceInfo) {
	if service == nil {
		return
	}
	delete(mi.Services, service.MatchKey)
}

// ServiceInfo the information of service
type ServiceInfo struct {
	Name     string            `json:"name,omitempty"`
	Group    string            `json:"group,omitempty"`
	Version  string            `json:"version,omitempty"`
	Protocol string            `json:"protocol,omitempty"`
	Path     string            `json:"path,omitempty"`
	Params   map[string]string `json:"params,omitempty"`

	ServiceKey string `json:"-"`
	MatchKey   string `json:"-"`
	URL        *URL   `json:"-"`
}

// nolint
func NewServiceInfoWithURL(url *URL) *ServiceInfo {
	service := NewServiceInfo(url.Service(), url.Group(), url.Version(), url.Protocol, url.Path, nil)
	service.URL = url
	// TODO includeKeys load dynamic
	p := make(map[string]string, 8)
	for _, keyInter := range IncludeKeys.Values() {
		key := keyInter.(string)
		value := url.GetParam(key, "")
		if len(value) != 0 {
			p[key] = value
		}
		for _, method := range url.Methods {
			value = url.GetMethodParam(method, key, "")
			if len(value) != 0 {
				p[method+"."+key] = value
			}
		}
	}
	service.Params = p
	return service
}

// nolint
func NewServiceInfo(name, group, version, protocol, path string, params map[string]string) *ServiceInfo {
	serviceKey := ServiceKey(name, group, version)
	matchKey := MatchKey(serviceKey, protocol)
	return &ServiceInfo{
		Name:       name,
		Group:      group,
		Version:    version,
		Protocol:   protocol,
		Path:       path,
		Params:     params,
		ServiceKey: serviceKey,
		MatchKey:   matchKey,
	}
}

// nolint
func (si *ServiceInfo) JavaClassName() string {
	return "org.apache.dubbo.metadata.MetadataInfo$ServiceInfo"
}

// nolint
func (si *ServiceInfo) GetMethods() []string {
	if si.Params[constant.METHODS_KEY] != "" {
		s := si.Params[constant.METHODS_KEY]
		return strings.Split(s, ",")
	}
	methods := make([]string, 8)
	for k, _ := range si.Params {
		ms := strings.Index(k, ".")
		if ms > 0 {
			methods = append(methods, k[0:ms])
		}
	}
	return methods
}

// nolint
func (si *ServiceInfo) GetParams() url.Values {
	v := url.Values{}
	for k, p := range si.Params {
		ms := strings.Index(k, ".")
		if ms > 0 {
			v.Set("methods."+k, p)
		} else {
			v.Set(k, p)
		}
	}
	return v
}

// nolint
func (si *ServiceInfo) GetMatchKey() string {
	if si.MatchKey != "" {
		return si.MatchKey
	}
	serviceKey := si.GetServiceKey()
	si.MatchKey = MatchKey(serviceKey, si.Protocol)
	return si.MatchKey
}

// nolint
func (si *ServiceInfo) GetServiceKey() string {
	if si.ServiceKey != "" {
		return si.ServiceKey
	}
	si.ServiceKey = ServiceKey(si.Name, si.Group, si.Version)
	return si.ServiceKey
}
