package kube

import (
	"regexp"
	"strings"

	"k8s.io/apimachinery/pkg/runtime/schema"
)

var versionRegex = regexp.MustCompile(`^v\d((alpha|beta)\d)?|\*$`)

func ParseKindSelector(input string) (string, string, string, string) {
	parts := strings.Split(input, "/")
	if len(parts) > 0 {
		parts = append(parts[:len(parts)-1], strings.Split(parts[len(parts)-1], ".")...)
	}
	switch len(parts) {
	case 1:
		// we have only kind
		return "*", "*", parts[0], ""
	case 2:
		// `*/*` means all resources and subresources
		if parts[0] == "*" && parts[1] == "*" {
			return "*", "*", "*", "*"
		}
		// detect the `*/subresource` case when part[1] is all lowercase
		if parts[0] == "*" && strings.ToLower(parts[1]) == parts[1] {
			return "*", "*", parts[0], parts[1]
		}
		// if the first part is `*` or a version we have version/kind
		if versionRegex.MatchString(parts[0]) {
			return "*", parts[0], parts[1], ""
		}
		// we have kind/subresource
		return "*", "*", parts[0], parts[1]
	case 3:
		// if the first part is `*` or a version we have version/kind/subresource
		if versionRegex.MatchString(parts[0]) {
			return "*", parts[0], parts[1], parts[2]
		}
		// we have group/version/kind
		return parts[0], parts[1], parts[2], ""
	case 4:
		// we have group/version/kind/subresource
		return parts[0], parts[1], parts[2], parts[3]
	default:
		return "", "", "", ""
	}
}

// GetKindFromGVK - get kind and APIVersion from GVK
func GetKindFromGVK(str string) (string, string) {
	parts := strings.Split(str, "/")
	switch len(parts) {
	case 1:
		return "", formatSubresource(str)
	case 2:
		if parts[0] == "*" && parts[1] == "*" {
			return "", parts[0] + "/" + parts[1]
		}
		if versionRegex.MatchString(parts[0]) {
			return parts[0], formatSubresource(parts[1])
		}
		return "", parts[0] + "/" + parts[1]
	case 3:
		if versionRegex.MatchString(parts[0]) {
			return parts[0], parts[1] + "/" + parts[2]
		}
		return parts[0] + "/" + parts[1], formatSubresource(parts[2])
	case 4:
		return parts[0] + "/" + parts[1], parts[2] + "/" + parts[3]
	default:
		return "", ""
	}
}

func formatSubresource(s string) string {
	return strings.Replace(s, ".", "/", 1)
}

// SplitSubresource - split subresource from kind
func SplitSubresource(s string) (kind string, subresource string) {
	parts := strings.Split(s, "/")
	if len(parts) == 2 {
		return parts[0], parts[1]
	}

	return s, ""
}

// ContainsKind - check if kind is in list
func ContainsKind(list []string, kind string) bool {
	for _, e := range list {
		_, k := GetKindFromGVK(e)
		k, _ = SplitSubresource(k)
		if k == kind {
			return true
		}
	}
	return false
}

// GroupVersionMatches - check if the given group version matches the server resource group version.
// If the group version contains a wildcard, it will match any version, but the group must match. Returns false if the
// supplied group version is empty, that condition should be checked before calling this function.
func GroupVersionMatches(groupVersion, serverResourceGroupVersion string) bool {
	if strings.Contains(groupVersion, "*") {
		return strings.HasPrefix(serverResourceGroupVersion, strings.TrimSuffix(groupVersion, "*"))
	}

	gv, err := schema.ParseGroupVersion(groupVersion)
	if err == nil {
		serverResourceGV, _ := schema.ParseGroupVersion(serverResourceGroupVersion)
		return gv.Group == serverResourceGV.Group && gv.Version == serverResourceGV.Version
	}

	return false
}

// IsSubresource returns true if the resource is a subresource
func IsSubresource(resourceName string) bool {
	return strings.Contains(resourceName, "/")
}
