// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package kubernetes

import (
	"context"
	"fmt"
	"strings"

	"github.com/coreos/go-semver/semver"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// DetectLowestVersion returns lowest Kubernetes components versions in the cluster.
//
//nolint:gocyclo
func DetectLowestVersion(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions) (string, error) {
	k8sClient, err := cluster.K8sHelper(ctx)
	if err != nil {
		return "", fmt.Errorf("error building kubernetes client: %w", err)
	}

	apps := map[string]struct{}{
		"kube-apiserver":          {},
		"kube-controller-manager": {},
		"kube-proxy":              {},
		"kube-scheduler":          {},
	}

	pods, err := k8sClient.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{})
	if err != nil {
		return "", err
	}

	var version *semver.Version

	for _, pod := range pods.Items {
		app := pod.GetObjectMeta().GetLabels()["k8s-app"]
		if _, ok := apps[app]; !ok {
			continue
		}

		for _, container := range pod.Spec.Containers {
			if container.Name != app {
				continue
			}

			idx := strings.LastIndex(container.Image, ":")
			if idx == -1 {
				continue
			}

			v, err := semver.NewVersion(strings.TrimLeft(container.Image[idx+1:], "v"))
			if err != nil {
				options.Log("failed to parse %s container version %s", app, err)

				continue
			}

			if version == nil || v.LessThan(*version) {
				version = v
			}
		}
	}

	if version == nil {
		return "", fmt.Errorf("failed to detect lowest Kubernetes version")
	}

	return version.String(), nil
}
