/*
Copyright 2019 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 distributions

import (
	"fmt"
	"os"
	"path"
	"strings"

	"k8s.io/klog/v2"
)

// FindDistribution identifies the distribution on which we are running
func FindDistribution(rootfs string) (Distribution, error) {
	// All supported distros have an /etc/os-release file
	osReleaseBytes, err := os.ReadFile(path.Join(rootfs, "etc/os-release"))
	osRelease := make(map[string]string)
	if err == nil {
		for _, line := range strings.Split(string(osReleaseBytes), "\n") {
			line = strings.TrimSpace(line)
			if strings.HasPrefix(line, "ID=") {
				osRelease["ID"] = strings.Trim(line[3:], "\"")
			}
			if strings.HasPrefix(line, "VERSION_ID=") {
				osRelease["VERSION_ID"] = strings.Trim(line[11:], "\"")
			}
		}
	} else {
		return Distribution{}, fmt.Errorf("reading /etc/os-release: %v", err)
	}

	distro := fmt.Sprintf("%s-%s", osRelease["ID"], osRelease["VERSION_ID"])

	// Most distros have a fixed VERSION_ID
	switch distro {
	case "amzn-2":
		return DistributionAmazonLinux2, nil
	case "amzn-2023":
		return DistributionAmazonLinux2023, nil
	case "debian-10":
		return DistributionDebian10, nil
	case "debian-11":
		return DistributionDebian11, nil
	case "debian-12":
		return DistributionDebian12, nil
	case "debian-13":
		return DistributionDebian13, nil
	case "fedora-41":
		return DistributionFedora41, nil
	case "fedora-42":
		return DistributionFedora42, nil
	case "fedora-43":
		return DistributionFedora43, nil
	case "fedora-44":
		return DistributionFedora44, nil
	case "ubuntu-20.04":
		return DistributionUbuntu2004, nil
	case "ubuntu-22.04":
		return DistributionUbuntu2204, nil
	case "ubuntu-24.04":
		return DistributionUbuntu2404, nil
	case "ubuntu-25.10":
		return DistributionUbuntu2510, nil
	}

	// Some distros have a more verbose VERSION_ID
	if strings.HasPrefix(distro, "cos-") {
		return DistributionContainerOS, nil
	}
	if strings.HasPrefix(distro, "flatcar-") {
		return DistributionFlatcar, nil
	}
	if strings.HasPrefix(distro, "centos-9.") {
		return DistributionCentOS9, nil
	}
	if strings.HasPrefix(distro, "centos-10.") {
		return DistributionCentOS10, nil
	}
	if strings.HasPrefix(distro, "rhel-8.") {
		return DistributionRhel8, nil
	}
	if strings.HasPrefix(distro, "rhel-9.") {
		return DistributionRhel9, nil
	}
	if strings.HasPrefix(distro, "rhel-10.") {
		return DistributionRhel10, nil
	}
	if strings.HasPrefix(distro, "rocky-8.") {
		return DistributionRocky8, nil
	}
	if strings.HasPrefix(distro, "rocky-9.") {
		return DistributionRocky9, nil
	}
	if strings.HasPrefix(distro, "rocky-10.") {
		return DistributionRocky10, nil
	}
	// Some distros are not supported
	klog.V(2).Infof("Contents of /etc/os-release:\n%s", osReleaseBytes)
	return Distribution{}, fmt.Errorf("unsupported distro %q", distro)
}
