package operator

import (
	"context"
	"fmt"
	"testing"

	"github.com/go-logr/logr"
	"github.com/go-logr/zapr"
	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
	ctrl "sigs.k8s.io/controller-runtime"

	v1alpha1 "github.com/pfeifferj/container-mom-go/pkg/apis/containermom/v1alpha1"
	"github.com/pfeifferj/container-mom-go/pkg/config"
	"github.com/pfeifferj/container-mom-go/pkg/operator/mongodb/mock"
)

func setupTestLogger() logr.Logger {
	zapLog, err := zap.NewDevelopment()
	if err != nil {
		panic(fmt.Sprintf("failed to create zap logger: %v", err))
	}
	logger := zapr.NewLogger(zapLog)
	ctrl.SetLogger(logger)
	return logger
}

func TestOperator(t *testing.T) {
	// Create mock MongoDB
	mockMongo := mock.NewMockMongoDB()

	// Set up logging
	setupTestLogger()

	// Create test config
	cfg := &config.Config{
		ListenAddr: ":8081",
		MongoURI:   "mongodb://mock:27017", // Not actually used
	}

	// Create operator
	op := &Operator{
		config:  cfg,
		mongodb: mockMongo,
	}
	assert.NotNil(t, op)

	// Test deployment trigger
	ctx := context.Background()
	err := op.TriggerDeploymentReconcile(ctx, "test-deployment")
	assert.Error(t, err) // Should fail because deployment doesn't exist
}

func TestOperatorHealth(t *testing.T) {
	// Create mock MongoDB
	mockMongo := mock.NewMockMongoDB()

	// Set up logging
	setupTestLogger()

	// Create test config
	cfg := &config.Config{
		ListenAddr: ":8081",
		MongoURI:   "mongodb://mock:27017", // Not actually used
	}

	// Create operator
	op := &Operator{
		config:  cfg,
		mongodb: mockMongo,
	}
	assert.NotNil(t, op)
}

func TestOperatorBilling(t *testing.T) {
	op := &Operator{}

	t.Run("GetCurrentCustomer", func(t *testing.T) {
		customer, err := op.GetCurrentCustomer(context.Background())
		assert.NoError(t, err)
		assert.Equal(t, "default", customer.Name)
	})

	t.Run("GetResourceUsage", func(t *testing.T) {
		usage, err := op.GetResourceUsage(context.Background(), "test")
		assert.NoError(t, err)
		assert.NotNil(t, usage)
	})

	t.Run("GetBillingHistory", func(t *testing.T) {
		history, err := op.GetBillingHistory(context.Background(), "test")
		assert.NoError(t, err)
		assert.Empty(t, history)
	})

	t.Run("UpdateBillingPlan", func(t *testing.T) {
		err := op.UpdateBillingPlan(context.Background(), "test", "plan")
		assert.NoError(t, err)
	})

	t.Run("UpdateBillingStatus", func(t *testing.T) {
		status := v1alpha1.BillingStatus{
			Status:  "active",
			Message: "test status",
		}
		err := op.UpdateBillingStatus(context.Background(), "test", status)
		assert.NoError(t, err)
	})
}

func TestSchemeRegistration(t *testing.T) {
	// Verify that our scheme has the expected types registered
	gvk := v1alpha1.SchemeGroupVersion.WithKind("ContainerMomDeployment")
	obj, err := scheme.New(gvk)
	assert.NoError(t, err)
	assert.NotNil(t, obj)
	assert.IsType(t, &v1alpha1.ContainerMomDeployment{}, obj)

	// Test that we can create a list type
	listGVK := v1alpha1.SchemeGroupVersion.WithKind("ContainerMomDeploymentList")
	listObj, err := scheme.New(listGVK)
	assert.NoError(t, err)
	assert.NotNil(t, listObj)
	assert.IsType(t, &v1alpha1.ContainerMomDeploymentList{}, listObj)
}
