/*
Copyright 2025 The Kubernetes Authors.

Licensed 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 clientcmd

import (
	"fmt"
	"os"
	"path/filepath"
	"testing"
)

func TestModifyConfigWritesToFirstKubeconfigFile(t *testing.T) {
	const (
		contextNameA   = "context-a"
		contextNameB   = "context-b"
		newContextName = "new-context"
	)

	tempdir := t.TempDir()
	configFile1 := filepath.Join(tempdir, "kubeconfig-a")
	configFile2 := filepath.Join(tempdir, "kubeconfig-b")

	// The first kubeconfig has everything.
	err := os.WriteFile(configFile1, []byte(`
kind: Config
apiVersion: v1
clusters:
- cluster:
    api-version: v1
    server: https://kubernetes.default.svc:443
    certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  name: kubeconfig-cluster
contexts:
- context:
    cluster: kubeconfig-cluster
    namespace: default
    user: kubeconfig-user
  name: `+contextNameA+`
current-context: `+contextNameA+`
users:
- name: kubeconfig-user
  user:
    tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
`), os.FileMode(0755))

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

	// The second kubeconfig declares a new context and activates it.
	err = os.WriteFile(configFile2, []byte(`
kind: Config
apiVersion: v1
contexts:
- context:
    cluster: kubeconfig-cluster
    namespace: a-different-namespace
    user: kubeconfig-user
  name: `+contextNameB+`
current-context: `+contextNameB+`
`), os.FileMode(0755))

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

	// Set KUBECONFIG to the files, in descending alphabetical order.
	// This will be used to check that they don't get sorted.
	envVarValue := fmt.Sprintf("%s%c%s", configFile2, filepath.ListSeparator, configFile1)
	t.Setenv(RecommendedConfigPathEnvVar, envVarValue)

	// Load the kubeconfigs, change the active context, and call ModifyConfig.
	loadingRules := NewDefaultClientConfigLoadingRules()
	config, err := loadingRules.Load()

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

	newConfig := config.DeepCopy()
	newConfig.CurrentContext = newContextName
	err = ModifyConfig(loadingRules, *newConfig, false)
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	// Load the files again and check that only configFile2 was changed.
	config1, err := LoadFromFile(configFile1) // file sorts first, but was specified last
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if config1.CurrentContext != contextNameA {
		t.Errorf("Config should not be modified, but was. Expected %q, got %q", contextNameA, config1.CurrentContext)
	}

	config2, err := LoadFromFile(configFile2) // file sorts last, but was specified first
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	if config2.CurrentContext != newContextName {
		t.Errorf("Config should be modified, but was not. Expected %q, got %q", newContextName, config2.CurrentContext)
	}
}
