// Copyright 2025 Microsoft Corporation
//
// 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 ocm

import (
	"encoding/json"
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"

	arohcpv1alpha1 "github.com/openshift-online/ocm-sdk-go/arohcp/v1alpha1"
	cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"

	"github.com/Azure/ARO-HCP/internal/api/metadataapi"
)

type FakeTransport struct{}

func (t *FakeTransport) RoundTrip(*http.Request) (*http.Response, error) {
	return nil, nil
}

func TestInternalID(t *testing.T) {
	tests := []struct {
		name      string
		path      string
		kind      string
		id        string
		clusterID string
		expectErr bool
	}{
		{
			name:      "parse invalid internal ID",
			path:      "/invalid/internal/id",
			kind:      "",
			expectErr: true,
		},
		{
			name:      "parse v1 cluster",
			path:      "/api/clusters_mgmt/v1/clusters/abc",
			kind:      cmv1.ClusterKind,
			id:        "abc",
			clusterID: "abc",
			expectErr: false,
		},
		{
			name:      "parse aro_hcp v1alpha1 cluster",
			path:      "/api/aro_hcp/v1alpha1/clusters/abc",
			kind:      arohcpv1alpha1.ClusterKind,
			id:        "abc",
			clusterID: "abc",
			expectErr: false,
		},
		{
			name:      "parse v1 node pool",
			path:      "/api/clusters_mgmt/v1/clusters/abc/node_pools/def",
			kind:      cmv1.NodePoolKind,
			id:        "def",
			clusterID: "abc",
			expectErr: false,
		},
		{
			name:      "parse aro_hcp v1alpha1 node pool",
			path:      "/api/aro_hcp/v1alpha1/clusters/abc/node_pools/def",
			kind:      arohcpv1alpha1.NodePoolKind,
			id:        "def",
			clusterID: "abc",
			expectErr: false,
		},
		{
			name:      "parse v1 external auth",
			path:      "/api/clusters_mgmt/v1/clusters/abc/external_auth_config/external_auths/def",
			kind:      cmv1.ExternalAuthKind,
			id:        "def",
			clusterID: "abc",
			expectErr: false,
		},
		{
			name:      "parse aro_hcp v1alpha1 externalAuth",
			path:      "/api/aro_hcp/v1alpha1/clusters/abc/external_auth_config/external_auths/def",
			kind:      arohcpv1alpha1.ExternalAuthKind,
			id:        "def",
			clusterID: "abc",
			expectErr: false,
		},
		{
			name:      "parse aro_hcp v1alpha1 provision shard",
			path:      "/api/aro_hcp/v1alpha1/provision_shards/abc",
			kind:      arohcpv1alpha1.ProvisionShardKind,
			id:        "abc",
			expectErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			internalID, err := metadataapi.NewInternalID(tt.path)
			if tt.expectErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}

			transport := &FakeTransport{}

			if tt.expectErr {
				return
			}

			kind := internalID.Kind()
			assert.Equal(t, tt.kind, kind)

			id := internalID.ID()
			assert.Equal(t, tt.id, id)

			str := internalID.String()
			assert.Equal(t, tt.path, str)

			switch kind {
			case arohcpv1alpha1.ProvisionShardKind:
				_, ok := getAroHCPProvisionShardClient(internalID, transport)
				assert.True(t, ok, "failed to get provision shard client")
			default:
				clusterID := internalID.ClusterID()
				assert.Equal(t, tt.clusterID, clusterID)

				_, ok := getClusterClient(internalID, transport)
				assert.True(t, ok, "failed to get cluster client")
				_, ok = getAroHCPClusterClient(internalID, transport)
				assert.True(t, ok, "failed to get aro hcp cluster client")
			}

			if kind == arohcpv1alpha1.NodePoolKind {
				_, ok := GetNodePoolClient(internalID, transport)
				assert.True(t, ok, "failed to get node pool client")
			}

			if kind == arohcpv1alpha1.ExternalAuthKind {
				_, ok := GetExternalAuthClient(internalID, transport)
				assert.True(t, ok, "failed to get external auth client")
			}

			bytes, err := json.Marshal(internalID)
			if assert.NoError(t, err) {
				err = json.Unmarshal(bytes, &internalID)
				assert.NoError(t, err)
			}
		})
	}
}
