package options

import (
	"fmt"

	"github.com/spf13/pflag"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/tidbcloud/infra-provider/network-policy-controller/cmd/controller/app/config"
)

// Options is flags of manager.
type Options struct {
	cfg        *config.Config
	Kubeconfig string

	DNSPodSelector string
}

// New returns default running options
// nolint: gomnd // all constants are default config
func New() *Options {
	opt := &Options{
		cfg: &config.Config{
			MetricsBindAddress:     ":8080",
			WebhookPort:            9443,
			HealthProbeBindAddress: ":8081",
			EnableLeaderElection:   false,

			DNSNamespace: "kube-system",
		},
		Kubeconfig: "",

		DNSPodSelector: "k8s-app=kube-dns",
	}

	return opt
}

// AddFlags adds flags for manager.
func (opt *Options) AddFlags(fs *pflag.FlagSet) {
	fs.StringVar(&opt.Kubeconfig, "kubeconfig", opt.Kubeconfig,
		"kubeconfig for user cluster",
	)

	fs.StringVar(&opt.cfg.MetricsBindAddress, "metrics-bind-address", opt.cfg.MetricsBindAddress,
		"The address the metric endpoint binds to.",
	)
	fs.StringVar(&opt.cfg.HealthProbeBindAddress, "health-probe-bind-address", opt.cfg.HealthProbeBindAddress,
		"The address the probe endpoint binds to.",
	)
	fs.IntVar(&opt.cfg.WebhookPort, "webhook-port", opt.cfg.WebhookPort,
		"The port of manager webhook.",
	)
	fs.BoolVar(&opt.cfg.EnableLeaderElection, "enable-leader-election", opt.cfg.EnableLeaderElection,
		"Enable leader election for controller manager. "+
			"Enabling this will ensure there is only one active controller manager.",
	)

	fs.StringVar(&opt.DNSPodSelector, "dns-pod-selector", opt.DNSPodSelector,
		"Pod selector to select dns for network egress policy",
	)
	fs.StringVar(&opt.cfg.DNSNamespace, "dns-namespace", opt.cfg.DNSNamespace,
		"Namespace of dns for network egress policy",
	)

	fs.StringSliceVar(&opt.cfg.ControlPlaneCIDRs, "control-plane-cidrs", opt.cfg.ControlPlaneCIDRs, "cidrs of conrol plane")

	fs.StringSliceVar(&opt.cfg.LoadBalancerCIDRs, "load-balancer-cidrs", opt.cfg.LoadBalancerCIDRs, "cidrs of load balancer")
	fs.StringSliceVar(&opt.cfg.O11yCIDRs, "o11y-cidrs", opt.cfg.O11yCIDRs, "cidrs of o11y vpc endpoints")

}

// Config returns config of manager
// Validation of options can be done in here.
func (opt *Options) Config() (*config.Config, error) {
	if opt.cfg.Kubeconfig == nil {
		kubeconfig, err := clientcmd.BuildConfigFromFlags("", opt.Kubeconfig)
		if err != nil {
			return nil, fmt.Errorf("can't parse kubeconfig: %w", err)
		}

		opt.cfg.Kubeconfig = kubeconfig
	}

	if opt.cfg.DNSPodSelector == nil {
		dnsPodSelector, err := metav1.ParseToLabelSelector(opt.DNSPodSelector)
		if err != nil {
			return nil, fmt.Errorf("can't parse dns pod selector %s: %w", opt.DNSPodSelector, err)
		}

		opt.cfg.DNSPodSelector = dnsPodSelector
	}

	if len(opt.cfg.ControlPlaneCIDRs) == 0 {
		return nil, fmt.Errorf("control plane cidrs are not set")
	}
	if len(opt.cfg.LoadBalancerCIDRs) == 0 {
		return nil, fmt.Errorf("load balancer cidrs are not set")
	}
	if len(opt.cfg.O11yCIDRs) == 0 {
		return nil, fmt.Errorf("o11y cidrs are not set")
	}

	return opt.cfg, nil
}
