// 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 bufconnect

import (
	"errors"
	"fmt"
	"strings"

	"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/app"
)

// NewTokenProviderFromContainer creates a singleTokenProvider from the BUF_TOKEN environment variable
func NewTokenProviderFromContainer(container app.EnvContainer) (TokenProvider, error) {
	return newTokenProviderFromString(container.Env(tokenEnvKey), true)
}

// NewTokenProviderFromString creates a singleTokenProvider by the token provided
func NewTokenProviderFromString(token string) (TokenProvider, error) {
	return newTokenProviderFromString(token, false)
}

// newTokenProviderFromString returns a TokenProvider with auth keys from the provided token. The
// remote token is in the format: token1@remote1,token2@remote2.
// The special characters `@` and `,` are used as the splitters. The tokens and remote addresses
// do not contain these characters since they are enforced by the rules in BSR.
func newTokenProviderFromString(token string, isFromEnvVar bool) (TokenProvider, error) {
	if token == "" {
		return nopTokenProvider{}, nil
	}
	// Tokens for different remotes are separated by `,`. Using strings.Split to separate the string into remote tokens.
	tokens := strings.Split(token, ",")
	if len(tokens) == 1 {
		if strings.Contains(tokens[0], "@") {
			return newMultipleTokenProvider(tokens, isFromEnvVar)
		}
		return newSingleTokenProvider(tokens[0], isFromEnvVar)
	}
	return newMultipleTokenProvider(tokens, isFromEnvVar)
}

// singleTokenProvider is used to provide set of authentication tokenToAuthKey.
type singleTokenProvider struct {
	// true: the tokenSet is generated from environment variable tokenEnvKey
	// false: otherwise
	setBufTokenEnvVar bool
	token             string
}

func newSingleTokenProvider(token string, isFromEnvVar bool) (*singleTokenProvider, error) {
	if strings.Contains(token, "@") {
		return nil, errors.New("token cannot contain special character `@`")
	}
	if strings.Contains(token, ",") {
		return nil, errors.New("token cannot contain special character `,`")
	}
	if token == "" {
		return nil, errors.New("single token cannot be empty")
	}
	return &singleTokenProvider{
		setBufTokenEnvVar: isFromEnvVar,
		token:             token,
	}, nil
}

// RemoteToken finds the token by the remote address
func (t *singleTokenProvider) RemoteToken(address string) string {
	return t.token
}

func (t *singleTokenProvider) IsFromEnvVar() bool {
	return t.setBufTokenEnvVar
}

type multipleTokenProvider struct {
	addressToToken map[string]string
	isFromEnvVar   bool
}

func newMultipleTokenProvider(tokens []string, isFromEnvVar bool) (*multipleTokenProvider, error) {
	addressToToken := make(map[string]string)
	for _, token := range tokens {
		split := strings.Split(token, "@")
		if len(split) != 2 {
			return nil, fmt.Errorf("invalid token: %s", token)
		}
		if split[0] == "" || split[1] == "" {
			return nil, fmt.Errorf("invalid token: %s", token)
		}
		if strings.Contains(split[0], ":") {
			return nil, fmt.Errorf("invalid token: %s, token cannot contain special character `:`", token)
		}
		if strings.Contains(split[0], ",") {
			return nil, fmt.Errorf("invalid token: %s, token cannot contain special character `,`", token)
		}
		if _, ok := addressToToken[split[1]]; ok {
			return nil, fmt.Errorf("invalid token: %s, repeated remote adddress: %s", token, split[1])
		}
		addressToToken[split[1]] = split[0]
	}
	return &multipleTokenProvider{
		addressToToken: addressToToken,
		isFromEnvVar:   isFromEnvVar,
	}, nil
}

func (m *multipleTokenProvider) RemoteToken(address string) string {
	return m.addressToToken[address]
}

func (m *multipleTokenProvider) IsFromEnvVar() bool {
	return m.isFromEnvVar
}

type nopTokenProvider struct{}

func (nopTokenProvider) RemoteToken(string) string {
	return ""
}

func (nopTokenProvider) IsFromEnvVar() bool {
	return false
}
