// Package kubernetes provides Kubernetes-based implementations of port interfaces.
package kubernetes

import (
	"fmt"
	"os"
	"path/filepath"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

// ClientConfig holds configuration for the Kubernetes client.
type ClientConfig struct {
	// Namespace is the K8s namespace to operate in.
	Namespace string
	// Kubeconfig is the path to the kubeconfig file (optional, for local dev).
	Kubeconfig string
}

// NewClient creates a new Kubernetes clientset.
// When running in-cluster, it uses the service account token.
// When running locally, it uses the kubeconfig file.
func NewClient(cfg ClientConfig) (*kubernetes.Clientset, error) {
	var config *rest.Config
	var err error

	// Try in-cluster config first (when running in K8s)
	config, err = rest.InClusterConfig()
	if err != nil {
		// Fall back to kubeconfig for local development
		kubeconfigPath := cfg.Kubeconfig
		if kubeconfigPath == "" {
			kubeconfigPath = defaultKubeconfigPath()
		}

		config, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath)
		if err != nil {
			return nil, fmt.Errorf("failed to create k8s config: %w", err)
		}
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("failed to create k8s clientset: %w", err)
	}

	return clientset, nil
}

// NewClientOrNil creates a K8s client, returning nil if it fails.
// This is useful for graceful fallback to hardcoded projects.
func NewClientOrNil(cfg ClientConfig) *kubernetes.Clientset {
	client, err := NewClient(cfg)
	if err != nil {
		return nil
	}
	return client
}

// defaultKubeconfigPath returns the default kubeconfig path.
func defaultKubeconfigPath() string {
	if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig != "" {
		return kubeconfig
	}
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	return filepath.Join(home, ".kube", "config")
}
