package operator

import (
	"context"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	v1alpha1 "github.com/pfeifferj/container-mom-go/pkg/apis/containermom/v1alpha1"
	testutil "github.com/pfeifferj/container-mom-go/pkg/operator/testing"
)

func TestDeploymentController(t *testing.T) {
	// Set up environment variables for testing namespace determination
	oldOperatorNamespace := os.Getenv("OPERATOR_NAMESPACE")
	oldWatchNamespace := os.Getenv("WATCH_NAMESPACE")
	defer func() {
		os.Setenv("OPERATOR_NAMESPACE", oldOperatorNamespace)
		os.Setenv("WATCH_NAMESPACE", oldWatchNamespace)
	}()

	// Set the test namespace
	testNamespace := "container-mom-system"
	os.Setenv("OPERATOR_NAMESPACE", testNamespace)
	os.Unsetenv("WATCH_NAMESPACE")

	// Create fake k8s client
	k8sClient, err := testutil.NewFakeClient()
	if err != nil {
		t.Fatalf("Failed to create fake client: %v", err)
	}

	// Create test CR in Kubernetes first
	testCR := &v1alpha1.ContainerMomDeployment{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-deployment",
			Namespace: testNamespace,
		},
		Spec: v1alpha1.ContainerMomDeploymentSpec{
			Source: v1alpha1.SourceSpec{
				GitURL: "https://github.com/test/repo",
			},
			Resources: v1alpha1.ResourceRequirements{
				CPU:    "100m",
				Memory: "128Mi",
			},
			Clusters: []string{"local"},
		},
	}

	// Add CR to k8s
	err = k8sClient.Create(context.Background(), testCR)
	assert.NoError(t, err)

	// Create reconciler and controller
	reconciler := NewDeploymentReconciler(k8sClient)
	controller := NewDeploymentController(nil, reconciler, k8sClient)

	// Verify controller is created correctly
	assert.NotNil(t, controller)

	// Test basic functionality
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// Queue the deployment for reconciliation
	controller.EnqueueDeployment(testCR.Name)

	// Verify enqueue and full sync work
	err = controller.fullSync(ctx)
	assert.NoError(t, err)

	// Test reconciliation with environment variables
	err = controller.reconcileDeployment(ctx, testCR.Name)
	assert.NoError(t, err)

	// Test with a different namespace via WATCH_NAMESPACE
	differentNamespace := "different-namespace"
	os.Unsetenv("OPERATOR_NAMESPACE")
	os.Setenv("WATCH_NAMESPACE", differentNamespace)

	// Create a new CR in the different namespace
	differentCR := testCR.DeepCopy()
	differentCR.Namespace = differentNamespace
	differentCR.Name = "different-test-deployment"

	// Add CR to k8s
	err = k8sClient.Create(context.Background(), differentCR)
	assert.NoError(t, err)

	// Test reconciliation with different namespace
	err = controller.reconcileDeployment(ctx, differentCR.Name)
	assert.NoError(t, err)
}

func TestDeploymentDeletion(t *testing.T) {
	// Set up environment variables for testing namespace determination
	oldOperatorNamespace := os.Getenv("OPERATOR_NAMESPACE")
	oldWatchNamespace := os.Getenv("WATCH_NAMESPACE")
	defer func() {
		os.Setenv("OPERATOR_NAMESPACE", oldOperatorNamespace)
		os.Setenv("WATCH_NAMESPACE", oldWatchNamespace)
	}()

	// Set the test namespace
	testNamespace := "container-mom-system"
	os.Setenv("OPERATOR_NAMESPACE", testNamespace)
	os.Unsetenv("WATCH_NAMESPACE")

	// Create fake k8s client
	k8sClient, err := testutil.NewFakeClient()
	if err != nil {
		t.Fatalf("Failed to create fake client: %v", err)
	}

	// Create reconciler and controller
	reconciler := NewDeploymentReconciler(k8sClient)
	controller := NewDeploymentController(nil, reconciler, k8sClient)

	// Verify controller is created correctly
	assert.NotNil(t, controller)

	// Test basic functionality
	ctx := context.Background()

	// Test reconcile for non-existent CR should not error
	err = controller.reconcileDeployment(ctx, "non-existent-deployment")
	assert.NoError(t, err)
}
