package object

// Taken and modified from the Kubernetes plugin of CoreDNS, under Apache 2.0.

import (
	"fmt"
	"net/netip"
	"regexp"
	"slices"
	"strings"
	"time"

	api "k8s.io/api/core/v1"
	discovery "k8s.io/api/discovery/v1"
	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
)

// Endpoints is a stripped down discovery.EndpointSlice
// with only the items we need.
type Endpoints struct {
	Version               string
	Name                  string
	Namespace             string
	LastChangeTriggerTime time.Time
	Index                 string
	Addresses             []EndpointAddress
	Ports                 []Port

	*Empty
}

// EndpointAddress is a tuple that describes single IP address.
type EndpointAddress struct {
	// IP contains the IP address in binary format.
	IP       string
	Hostname string
}

// Port is a tuple that describes a single port.
type Port struct {
	Port     uint16
	Name     string
	Protocol string
}

// EndpointsKey returns a string using for the index.
func EndpointsKey(name, namespace string) string { return name + "." + namespace }

var hostnameRegexp = regexp.MustCompile(`^[-a-z0-9]{1,63}$`)

// EndpointSliceToEndpoints converts a *discovery.EndpointSlice to a *Endpoints.
func EndpointSliceToEndpoints(obj meta.Object) (meta.Object, error) {
	ends, ok := obj.(*discovery.EndpointSlice)
	if !ok {
		return nil, fmt.Errorf("unexpected object %v", obj)
	}
	e := &Endpoints{
		Version:   ends.GetResourceVersion(),
		Name:      ends.GetName(),
		Namespace: ends.GetNamespace(),
		Index:     EndpointsKey(ends.Labels[discovery.LabelServiceName], ends.GetNamespace()),
	}

	// In case of parse error, the value is time.Zero.
	e.LastChangeTriggerTime, _ = time.Parse(time.RFC3339Nano, ends.Annotations[api.EndpointsLastChangeTriggerTime])

	e.Ports = make([]Port, 0, len(ends.Ports))
	for _, p := range ends.Ports {
		if p.Port != nil && *p.Port >= 1 && *p.Port <= 0xffff &&
			p.Name != nil && *p.Name != "" && p.Protocol != nil {
			ep := Port{
				Port:     uint16(*p.Port),
				Name:     strings.ToLower(*p.Name),
				Protocol: strings.ToLower(string(*p.Protocol)),
			}
			e.Ports = append(e.Ports, ep)
		}
	}

	for _, end := range ends.Endpoints {
		if !endpointsliceReady(end.Conditions.Ready) {
			continue
		}

		var endHostname string
		if end.Hostname != nil {
			endHostname = *end.Hostname
		}
		if endHostname != "" && !hostnameRegexp.MatchString(endHostname) {
			endHostname = ""
		}

		for _, rawIP := range end.Addresses {
			parsedIP, err := netip.ParseAddr(rawIP)
			if err != nil || parsedIP.Zone() != "" {
				continue
			}
			parsedIP = parsedIP.Unmap()
			// The IP address is converted to a binary string, not human readable.
			// That way we don't need to parse it again later.
			ea := EndpointAddress{IP: string(parsedIP.AsSlice())}
			if endHostname != "" {
				ea.Hostname = endHostname
			} else {
				ea.Hostname = strings.ReplaceAll(strings.ReplaceAll(parsedIP.String(), ".", "-"), ":", "-")
			}
			e.Addresses = append(e.Addresses, ea)
		}
	}

	*ends = discovery.EndpointSlice{}

	return e, nil
}

func endpointsliceReady(ready *bool) bool {
	// Per API docs: a nil value indicates an unknown state. In most cases
	// consumers should interpret this unknown state as ready.
	if ready == nil {
		return true
	}
	return *ready
}

var _ runtime.Object = &Endpoints{}

// DeepCopyObject implements the ObjectKind interface.
func (e *Endpoints) DeepCopyObject() runtime.Object {
	e1 := &Endpoints{
		Version:   e.Version,
		Name:      e.Name,
		Namespace: e.Namespace,
		Index:     e.Index,
		Addresses: make([]EndpointAddress, len(e.Addresses)),
		Ports:     make([]Port, len(e.Ports)),
	}
	copy(e1.Addresses, e.Addresses)
	copy(e1.Ports, e.Ports)
	return e1
}

// GetNamespace implements the metav1.Object interface.
func (e *Endpoints) GetNamespace() string { return e.Namespace }

// SetNamespace implements the metav1.Object interface.
func (e *Endpoints) SetNamespace(namespace string) {}

// GetName implements the metav1.Object interface.
func (e *Endpoints) GetName() string { return e.Name }

// SetName implements the metav1.Object interface.
func (e *Endpoints) SetName(name string) {}

// GetResourceVersion implements the metav1.Object interface.
func (e *Endpoints) GetResourceVersion() string { return e.Version }

// SetResourceVersion implements the metav1.Object interface.
func (e *Endpoints) SetResourceVersion(version string) {}

// EndpointsModified checks if the update to an endpoint is something
// that matters to us or if they are effectively equivalent.
func EndpointsModified(a, b *Endpoints) bool {
	if a.Index != b.Index {
		return true
	}
	if !slices.Equal(a.Addresses, b.Addresses) {
		return true
	}
	if !slices.Equal(a.Ports, b.Ports) {
		return true
	}
	return false
}
