/*
Copyright 2024 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package statusz

import (
	"time"

	"k8s.io/apimachinery/pkg/util/version"
	"k8s.io/component-base/compatibility"
	"k8s.io/klog/v2"

	compbasemetrics "k8s.io/component-base/metrics"
	utilversion "k8s.io/component-base/version"
)

type statuszRegistry interface {
	processStartTime() time.Time
	goVersion() string
	binaryVersion() *version.Version
	emulationVersion() *version.Version
	paths() []string
	deprecatedVersions() map[string]bool
}

type registry struct {
	// componentGlobalsRegistry compatibility.ComponentGlobalsRegistry
	effectiveVersion compatibility.EffectiveVersion
	// listedPaths is an alphabetically sorted list of paths to be reported at /.
	listedPaths []string
	// deprecatedVersionsMap is a map of deprecated statusz versions.
	deprecatedVersionsMap map[string]bool
}

// Option is a function to configure registry.
type Option func(reg *registry)

// WithListedPaths returns an Option to configure the ListedPaths.
func WithListedPaths(listedPaths []string) Option {
	cpyListedPaths := make([]string, len(listedPaths))
	copy(cpyListedPaths, listedPaths)

	return func(reg *registry) { reg.listedPaths = cpyListedPaths }
}

func (*registry) processStartTime() time.Time {
	start, err := compbasemetrics.GetProcessStart()
	if err != nil {
		klog.Errorf("Could not get process start time, %v", err)
	}

	return time.Unix(int64(start), 0)
}

func (*registry) goVersion() string {
	return utilversion.Get().GoVersion
}

func (r *registry) binaryVersion() *version.Version {
	if r.effectiveVersion != nil {
		return r.effectiveVersion.BinaryVersion()
	}
	return version.MustParse(utilversion.Get().String())
}

func (r *registry) emulationVersion() *version.Version {
	if r.effectiveVersion != nil {
		return r.effectiveVersion.EmulationVersion()
	}

	return nil
}

func (r *registry) paths() []string {
	if r.listedPaths != nil {
		return r.listedPaths
	}

	return nil
}

func (r *registry) deprecatedVersions() map[string]bool {
	return r.deprecatedVersionsMap
}
