package agent

import (
	"context"
	"fmt"
	"strconv"

	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/api"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/module/remote_development/agent/k8s"
	rdutil "gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/module/remote_development/agent/util"
	corev1 "k8s.io/api/core/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

type uniqueNamespaceHandler struct {
	k8sClient k8s.Client
	agentKey  api.AgentKey
}

func newUniqueNamespaceHandler(k8sClient k8s.Client, agentKey api.AgentKey) *uniqueNamespaceHandler {
	return &uniqueNamespaceHandler{
		k8sClient: k8sClient,
		agentKey:  agentKey,
	}
}

func (h *uniqueNamespaceHandler) IsTerminated(ctx context.Context, info *WorkspaceRailsInfo, _ []*unstructured.Unstructured) (bool, error) {
	_, err := h.k8sClient.Get(ctx, namespaceGVR, "", info.Namespace)
	if err != nil {
		if k8serrors.IsNotFound(err) {
			return true, nil
		}
		return false, err
	}
	return false, nil
}

func (h *uniqueNamespaceHandler) Terminate(ctx context.Context, info *WorkspaceRailsInfo, _ []*unstructured.Unstructured) <-chan *ErrorDetails {
	err := h.k8sClient.Delete(ctx, namespaceGVR, "", info.Namespace)
	if err != nil {
		return rdutil.ToAsync(newErrorDetails(ErrorTypeKubernetes, fmt.Sprintf("failed to terminate workspace %s: %s", info.Name, err)))
	}
	return nil
}

func (h *uniqueNamespaceHandler) Create(ctx context.Context, info *WorkspaceRailsInfo) <-chan *ErrorDetails {
	_, err := h.k8sClient.UpdateOrCreate(ctx, namespaceGVR, "", &corev1.Namespace{
		ObjectMeta: metav1.ObjectMeta{
			Name: info.Namespace,
			Labels: map[string]string{
				api.AgentIDKey: strconv.FormatInt(h.agentKey.ID, 10),
			},
		},
		TypeMeta: metav1.TypeMeta{
			APIVersion: "v1",
			Kind:       "Namespace",
		},
	}, true)
	if err != nil {
		errMsg := fmt.Sprintf("failed to create/update namespace %s: %s", info.Namespace, err.Error())
		return rdutil.ToAsync[*ErrorDetails](newErrorDetails(ErrorTypeKubernetes, errMsg))
	}
	return nil
}
