package netd

import (
	"context"
	"fmt"
	"net"

	"github.com/go-logr/logr"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/intstr"
	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/log"

	apiconfig "github.com/sandbox0-ai/sandbox0/infra-operator/api/config"
	"github.com/sandbox0-ai/sandbox0/infra-operator/internal/controller/pkg/common"
	meteringsvc "github.com/sandbox0-ai/sandbox0/infra-operator/internal/controller/services/metering"
	redissvc "github.com/sandbox0-ai/sandbox0/infra-operator/internal/controller/services/redis"
	sandboxobssvc "github.com/sandbox0-ai/sandbox0/infra-operator/internal/controller/services/sandboxobservability"
	infraplan "github.com/sandbox0-ai/sandbox0/infra-operator/internal/plan"
	pkginternalauth "github.com/sandbox0-ai/sandbox0/pkg/internalauth"
)

type Reconciler struct {
	Resources *common.ResourceManager
}

func NewReconciler(resources *common.ResourceManager) *Reconciler {
	return &Reconciler{Resources: resources}
}

func (r *Reconciler) Reconcile(ctx context.Context, imageRepo, imageTag string, compiledPlan *infraplan.InfraPlan) error {
	logger := log.FromContext(ctx)
	if compiledPlan == nil {
		return fmt.Errorf("compiled plan is required")
	}
	if !compiledPlan.Netd.Enabled {
		logger.Info("netd is disabled, skipping")
		return nil
	}
	if !compiledPlan.Components.HasDataPlane {
		logger.Info("Data-plane services are disabled, skipping netd")
		return nil
	}

	scope := compiledPlan.Scope
	name := fmt.Sprintf("%s-netd", scope.Name)
	labels := common.GetServiceLabels(scope.Name, "netd")
	image := fmt.Sprintf("%s:%s", imageRepo, imageTag)
	pullPolicy := corev1.PullIfNotPresent
	if r.Resources.ImagePullPolicy != nil {
		pullPolicy = *r.Resources.ImagePullPolicy
	}

	config := &apiconfig.NetdConfig{}
	if compiledPlan.Netd.Config != nil {
		config = compiledPlan.Netd.Config.DeepCopy()
	}
	runtimeClassName := compiledPlan.Netd.RuntimeClassName
	nodeSelector := compiledPlan.Netd.NodeSelector
	tolerations := compiledPlan.Netd.Tolerations
	if config.NodeName == "" {
		config.NodeName = "${NODE_NAME}"
	}
	if config.MetricsPort == 0 {
		config.MetricsPort = 9091
	}
	if config.HealthPort == 0 {
		config.HealthPort = 8081
	}
	if config.ClusterDNSCIDR == "" {
		cidr, err := resolveClusterDNSCIDR(ctx, r.Resources.Client, logger)
		if err != nil {
			return err
		}
		config.ClusterDNSCIDR = cidr
	}
	if err := redissvc.ApplyNetdRedisConfig(ctx, r.Resources.Client, compiledPlan.Scope.Owner(), config); err != nil {
		return err
	}
	if dsn, err := compiledPlan.DatabaseDSN(ctx, r.Resources.Client); err == nil {
		config.DatabaseURL = dsn
	}
	config.RegionID = compiledPlan.Netd.RegionID
	config.ClusterID = compiledPlan.Netd.ClusterID
	if err := meteringsvc.ApplyNetdConfig(ctx, r.Resources.Client, compiledPlan.Scope.Owner(), config); err != nil {
		return err
	}
	if config.EgressAuthResolverURL == "" {
		config.EgressAuthResolverURL = compiledPlan.Netd.EgressAuthResolverURL
	}
	if err := sandboxobssvc.ApplyNetdConfig(ctx, r.Resources.Client, compiledPlan.Scope.Owner(), compiledPlan.Services.ClusterGateway.URL, config); err != nil {
		return err
	}
	mitmCASecretName, err := r.resolveMITMCASecretName(ctx, compiledPlan, labels)
	if err != nil {
		return err
	}
	keySecretName, privateKeyKey, _ := compiledPlan.DataPlaneKeyRefs()
	if mitmCASecretName != "" {
		if config.MITMCACertPath == "" {
			config.MITMCACertPath = "/tls/ca.crt"
		}
		if config.MITMCAKeyPath == "" {
			config.MITMCAKeyPath = "/tls/ca.key"
		}
	}
	configRef, err := r.Resources.ReconcileHashedServiceConfigMapWithScope(ctx, scope, name, labels, config)
	if err != nil {
		return err
	}
	podAnnotations := configRef.PodAnnotations()

	volumes := []corev1.Volume{
		{
			Name: "config",
			VolumeSource: corev1.VolumeSource{
				ConfigMap: &corev1.ConfigMapVolumeSource{
					LocalObjectReference: corev1.LocalObjectReference{Name: configRef.ConfigMapName},
				},
			},
		},
		{
			Name: "bpf-fs",
			VolumeSource: corev1.VolumeSource{
				HostPath: &corev1.HostPathVolumeSource{
					Path: "/sys/fs/bpf",
					Type: func() *corev1.HostPathType { t := corev1.HostPathDirectoryOrCreate; return &t }(),
				},
			},
		},
		{
			Name: "modules",
			VolumeSource: corev1.VolumeSource{
				HostPath: &corev1.HostPathVolumeSource{
					Path: "/lib/modules",
					Type: func() *corev1.HostPathType { t := corev1.HostPathDirectoryOrCreate; return &t }(),
				},
			},
		},
		{
			Name: "run",
			VolumeSource: corev1.VolumeSource{
				EmptyDir: &corev1.EmptyDirVolumeSource{},
			},
		},
		{
			Name: "internal-jwt-private-key",
			VolumeSource: corev1.VolumeSource{
				Secret: &corev1.SecretVolumeSource{
					SecretName: keySecretName,
					Items: []corev1.KeyToPath{{
						Key:  privateKeyKey,
						Path: "internal_jwt_private.key",
					}},
				},
			},
		},
	}
	if mitmCASecretName != "" {
		volumes = append(volumes, corev1.Volume{
			Name: "mitm-ca",
			VolumeSource: corev1.VolumeSource{
				Secret: &corev1.SecretVolumeSource{
					SecretName: mitmCASecretName,
				},
			},
		})
	}

	volumeMounts := []corev1.VolumeMount{
		{
			Name:      "config",
			MountPath: "/config/config.yaml",
			SubPath:   "config.yaml",
			ReadOnly:  true,
		},
		{
			Name:      "bpf-fs",
			MountPath: "/sys/fs/bpf",
		},
		{
			Name:      "modules",
			MountPath: "/lib/modules",
			ReadOnly:  true,
		},
		{
			Name:      "run",
			MountPath: "/run",
		},
		{
			Name:      "internal-jwt-private-key",
			MountPath: pkginternalauth.DefaultInternalJWTPrivateKeyPath,
			SubPath:   "internal_jwt_private.key",
			ReadOnly:  true,
		},
	}
	if mitmCASecretName != "" {
		volumeMounts = append(volumeMounts, corev1.VolumeMount{
			Name:      "mitm-ca",
			MountPath: "/tls",
			ReadOnly:  true,
		})
	}

	desired := &appsv1.DaemonSet{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: scope.Namespace,
		},
		Spec: appsv1.DaemonSetSpec{
			Selector: &metav1.LabelSelector{
				MatchLabels: labels,
			},
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels:      labels,
					Annotations: common.EnsurePodTemplateAnnotations(podAnnotations),
				},
				Spec: corev1.PodSpec{
					ServiceAccountName: name,
					RuntimeClassName:   runtimeClassName,
					HostNetwork:        true,
					DNSPolicy:          corev1.DNSClusterFirstWithHostNet,
					NodeSelector:       nodeSelector,
					Tolerations:        tolerations,
					Containers: []corev1.Container{
						{
							Name:            "netd",
							Image:           image,
							ImagePullPolicy: pullPolicy,
							Env: common.AppendObservabilityEnvVars([]corev1.EnvVar{
								{
									Name:  "SERVICE",
									Value: "netd",
								},
								{
									Name:  "CONFIG_PATH",
									Value: "/config/config.yaml",
								},
								{
									Name: "NODE_NAME",
									ValueFrom: &corev1.EnvVarSource{
										FieldRef: &corev1.ObjectFieldSelector{FieldPath: "spec.nodeName"},
									},
								},
							}, scope.Owner(), common.ObservabilityEnvConfig{
								ServiceName: "netd",
								RegionID:    compiledPlan.Netd.RegionID,
								ClusterID:   compiledPlan.Netd.ClusterID,
							}),
							Ports: []corev1.ContainerPort{
								{Name: "metrics", ContainerPort: int32(config.MetricsPort)},
								{Name: "health", ContainerPort: int32(config.HealthPort)},
							},
							SecurityContext: &corev1.SecurityContext{
								AllowPrivilegeEscalation: common.BoolPtr(false),
								Privileged:               common.BoolPtr(false),
								Capabilities: &corev1.Capabilities{
									Add: []corev1.Capability{"NET_ADMIN", "NET_RAW"},
								},
							},
							LivenessProbe: &corev1.Probe{
								ProbeHandler: corev1.ProbeHandler{
									HTTPGet: &corev1.HTTPGetAction{
										Path: "/healthz",
										Port: intstr.FromString("health"),
									},
								},
								InitialDelaySeconds: 10,
								PeriodSeconds:       10,
							},
							ReadinessProbe: &corev1.Probe{
								ProbeHandler: corev1.ProbeHandler{
									HTTPGet: &corev1.HTTPGetAction{
										Path: "/readyz",
										Port: intstr.FromString("health"),
									},
								},
								InitialDelaySeconds: 5,
								PeriodSeconds:       5,
							},
							VolumeMounts: volumeMounts,
						},
					},
					Volumes: volumes,
				},
			},
		},
	}

	return r.Resources.ApplyDaemonSetWithScope(ctx, scope, desired)
}

func (r *Reconciler) resolveMITMCASecretName(ctx context.Context, compiledPlan *infraplan.InfraPlan, labels map[string]string) (string, error) {
	return EnsureMITMCASecretWithScope(ctx, r.Resources, compiledPlan.Scope, compiledPlan, labels)
}

func resolveClusterDNSCIDR(ctx context.Context, client ctrlclient.Client, logger logr.Logger) (string, error) {
	if client == nil {
		return "", fmt.Errorf("client is nil")
	}
	serviceNames := []string{"kube-dns", "coredns"}
	for _, name := range serviceNames {
		svc := &corev1.Service{}
		if err := client.Get(ctx, types.NamespacedName{Name: name, Namespace: "kube-system"}, svc); err != nil {
			continue
		}
		if svc.Spec.ClusterIP == "" || svc.Spec.ClusterIP == "None" {
			continue
		}
		ip := net.ParseIP(svc.Spec.ClusterIP)
		if ip == nil {
			continue
		}
		if ip.To4() != nil {
			return ip.String() + "/32", nil
		}
		return ip.String() + "/128", nil
	}
	return "", fmt.Errorf("failed to resolve cluster DNS CIDR from kube-dns/coredns, please specify it in the netd config")
}
