package imports

import (
	"context"
	"testing"

	"github.com/stretchr/testify/suite"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
)

const infraTestNamespace = "proj-123"

type importControllerSuite struct {
	suite.Suite
	network  *cloudv1.Network
	provider *cloudv1.Provider
}

func TestImportControllerSuite(t *testing.T) {
	suite.Run(t, new(importControllerSuite))
}

func (s *importControllerSuite) SetupSuite() {
	provider := &cloudv1.Provider{
		Spec: cloudv1.ProviderSpec{
			Type: "dummy-provider-type",
		},
	}
	provider.Name = "dummy-provider"
	provider.Namespace = infraTestNamespace
	s.provider = provider

	network := &cloudv1.Network{
		Spec: cloudv1.NetworkSpec{
			Provider: "dummy-provider",
		},
	}
	network.Name = "dummy-network"
	network.Namespace = infraTestNamespace
	s.network = network
}

func (s *importControllerSuite) TestConnectWithoutClusterObject() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	scheme := runtime.NewScheme()
	s.Require().NoError(cloudv1.AddToScheme(scheme))

	imp := new(cloudv1.Import)
	imp.Name = "import-123"
	imp.Namespace = infraTestNamespace
	imp.Annotations = map[string]string{
		cloudv1.ImportAnnotationKeyNetworkName: s.network.Name,
	}
	imp.Labels = map[string]string{
		cloudv1.ProviderTypeLabel: "dummy-provider-type",
		cloudv1.RegionLabel:       "dummy-region",
	}

	infraCli := fake.NewClientBuilder().
		WithScheme(scheme).
		WithRuntimeObjects(
			imp,
			s.network,
			s.provider,
		).
		WithStatusSubresource(imp, s.network, s.provider).
		Build()

	imp2 := new(cloudv1.Import)
	s.Require().NoError(infraCli.Get(ctx, client.ObjectKey{Name: imp.Name, Namespace: infraTestNamespace}, imp2))
	s.Require().Equal(imp.Name, imp2.Name)
	s.Require().Equal(imp.Namespace, imp2.Namespace)

	ic := &importConnector{
		client:     infraCli,
		envBuilder: NewMockEnvBuilder(),
	}
	_, err := ic.Connect(ctx, imp2)
	s.Require().NoError(err)
}

func (s *importControllerSuite) TestDeleteWithoutClusterObject() {
	var err error
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	scheme := runtime.NewScheme()
	s.Require().NoError(cloudv1.AddToScheme(scheme))

	imp := new(cloudv1.Import)
	imp.Name = "import-123"
	imp.Namespace = infraTestNamespace
	imp.Annotations = map[string]string{
		cloudv1.ImportAnnotationKeyNetworkName: s.network.Name,
	}
	imp.Labels = map[string]string{
		cloudv1.ProviderTypeLabel: "dummy-provider-type",
		cloudv1.RegionLabel:       "dummy-region",
	}

	infraCli := fake.NewClientBuilder().
		WithScheme(scheme).
		WithRuntimeObjects(
			imp,
			s.network,
			s.provider,
		).
		WithStatusSubresource(imp, s.network, s.provider).
		Build()

	imp2 := new(cloudv1.Import)
	s.Require().NoError(infraCli.Get(ctx, client.ObjectKey{Name: imp.Name, Namespace: infraTestNamespace}, imp2))
	s.Require().Equal(imp.Name, imp2.Name)
	s.Require().Equal(imp.Namespace, imp2.Namespace)

	ic := &importConnector{
		client:     infraCli,
		envBuilder: NewMockEnvBuilder(),
	}
	ci, err := ic.Connect(ctx, imp2)
	s.Require().NoError(err)
	_, err = ci.Delete(ctx, imp2)
	s.Require().NoError(err)
	s.Require().NoError(infraCli.Delete(ctx, imp2))
	imp3 := new(cloudv1.Import)
	s.Require().Error(infraCli.Get(ctx, client.ObjectKey{Name: imp.Name, Namespace: infraTestNamespace}, imp3))
}
