/* SPDX-License-Identifier: MIT
 *
 * Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
 */

package version

import (
	"fmt"

	"golang.org/x/sys/windows"
	"golang.org/x/sys/windows/registry"
)

const (
	PRODUCT_UNDEFINED                           = 0x00000000
	PRODUCT_ULTIMATE                            = 0x00000001
	PRODUCT_HOME_BASIC                          = 0x00000002
	PRODUCT_HOME_PREMIUM                        = 0x00000003
	PRODUCT_ENTERPRISE                          = 0x00000004
	PRODUCT_HOME_BASIC_N                        = 0x00000005
	PRODUCT_BUSINESS                            = 0x00000006
	PRODUCT_STANDARD_SERVER                     = 0x00000007
	PRODUCT_DATACENTER_SERVER                   = 0x00000008
	PRODUCT_SMALLBUSINESS_SERVER                = 0x00000009
	PRODUCT_ENTERPRISE_SERVER                   = 0x0000000A
	PRODUCT_STARTER                             = 0x0000000B
	PRODUCT_DATACENTER_SERVER_CORE              = 0x0000000C
	PRODUCT_STANDARD_SERVER_CORE                = 0x0000000D
	PRODUCT_ENTERPRISE_SERVER_CORE              = 0x0000000E
	PRODUCT_ENTERPRISE_SERVER_IA64              = 0x0000000F
	PRODUCT_BUSINESS_N                          = 0x00000010
	PRODUCT_WEB_SERVER                          = 0x00000011
	PRODUCT_CLUSTER_SERVER                      = 0x00000012
	PRODUCT_HOME_SERVER                         = 0x00000013
	PRODUCT_STORAGE_EXPRESS_SERVER              = 0x00000014
	PRODUCT_STORAGE_STANDARD_SERVER             = 0x00000015
	PRODUCT_STORAGE_WORKGROUP_SERVER            = 0x00000016
	PRODUCT_STORAGE_ENTERPRISE_SERVER           = 0x00000017
	PRODUCT_SERVER_FOR_SMALLBUSINESS            = 0x00000018
	PRODUCT_SMALLBUSINESS_SERVER_PREMIUM        = 0x00000019
	PRODUCT_HOME_PREMIUM_N                      = 0x0000001A
	PRODUCT_ENTERPRISE_N                        = 0x0000001B
	PRODUCT_ULTIMATE_N                          = 0x0000001C
	PRODUCT_WEB_SERVER_CORE                     = 0x0000001D
	PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT    = 0x0000001E
	PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY      = 0x0000001F
	PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING     = 0x00000020
	PRODUCT_SERVER_FOUNDATION                   = 0x00000021
	PRODUCT_HOME_PREMIUM_SERVER                 = 0x00000022
	PRODUCT_SERVER_FOR_SMALLBUSINESS_V          = 0x00000023
	PRODUCT_STANDARD_SERVER_V                   = 0x00000024
	PRODUCT_DATACENTER_SERVER_V                 = 0x00000025
	PRODUCT_ENTERPRISE_SERVER_V                 = 0x00000026
	PRODUCT_DATACENTER_SERVER_CORE_V            = 0x00000027
	PRODUCT_STANDARD_SERVER_CORE_V              = 0x00000028
	PRODUCT_ENTERPRISE_SERVER_CORE_V            = 0x00000029
	PRODUCT_HYPERV                              = 0x0000002A
	PRODUCT_STORAGE_EXPRESS_SERVER_CORE         = 0x0000002B
	PRODUCT_STORAGE_STANDARD_SERVER_CORE        = 0x0000002C
	PRODUCT_STORAGE_WORKGROUP_SERVER_CORE       = 0x0000002D
	PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE      = 0x0000002E
	PRODUCT_STARTER_N                           = 0x0000002F
	PRODUCT_PROFESSIONAL                        = 0x00000030
	PRODUCT_PROFESSIONAL_N                      = 0x00000031
	PRODUCT_SB_SOLUTION_SERVER                  = 0x00000032
	PRODUCT_SERVER_FOR_SB_SOLUTIONS             = 0x00000033
	PRODUCT_STANDARD_SERVER_SOLUTIONS           = 0x00000034
	PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE      = 0x00000035
	PRODUCT_SB_SOLUTION_SERVER_EM               = 0x00000036
	PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM          = 0x00000037
	PRODUCT_SOLUTION_EMBEDDEDSERVER             = 0x00000038
	PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE        = 0x00000039
	PRODUCT_PROFESSIONAL_EMBEDDED               = 0x0000003A
	PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT       = 0x0000003B
	PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL       = 0x0000003C
	PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC    = 0x0000003D
	PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC    = 0x0000003E
	PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE   = 0x0000003F
	PRODUCT_CLUSTER_SERVER_V                    = 0x00000040
	PRODUCT_EMBEDDED                            = 0x00000041
	PRODUCT_STARTER_E                           = 0x00000042
	PRODUCT_HOME_BASIC_E                        = 0x00000043
	PRODUCT_HOME_PREMIUM_E                      = 0x00000044
	PRODUCT_PROFESSIONAL_E                      = 0x00000045
	PRODUCT_ENTERPRISE_E                        = 0x00000046
	PRODUCT_ULTIMATE_E                          = 0x00000047
	PRODUCT_ENTERPRISE_EVALUATION               = 0x00000048
	PRODUCT_MULTIPOINT_STANDARD_SERVER          = 0x0000004C
	PRODUCT_MULTIPOINT_PREMIUM_SERVER           = 0x0000004D
	PRODUCT_STANDARD_EVALUATION_SERVER          = 0x0000004F
	PRODUCT_DATACENTER_EVALUATION_SERVER        = 0x00000050
	PRODUCT_ENTERPRISE_N_EVALUATION             = 0x00000054
	PRODUCT_EMBEDDED_AUTOMOTIVE                 = 0x00000055
	PRODUCT_EMBEDDED_INDUSTRY_A                 = 0x00000056
	PRODUCT_THINPC                              = 0x00000057
	PRODUCT_EMBEDDED_A                          = 0x00000058
	PRODUCT_EMBEDDED_INDUSTRY                   = 0x00000059
	PRODUCT_EMBEDDED_E                          = 0x0000005A
	PRODUCT_EMBEDDED_INDUSTRY_E                 = 0x0000005B
	PRODUCT_EMBEDDED_INDUSTRY_A_E               = 0x0000005C
	PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER = 0x0000005F
	PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER  = 0x00000060
	PRODUCT_CORE_ARM                            = 0x00000061
	PRODUCT_CORE_N                              = 0x00000062
	PRODUCT_CORE_COUNTRYSPECIFIC                = 0x00000063
	PRODUCT_CORE_SINGLELANGUAGE                 = 0x00000064
	PRODUCT_CORE                                = 0x00000065
	PRODUCT_PROFESSIONAL_WMC                    = 0x00000067
	PRODUCT_EMBEDDED_INDUSTRY_EVAL              = 0x00000069
	PRODUCT_EMBEDDED_INDUSTRY_E_EVAL            = 0x0000006A
	PRODUCT_EMBEDDED_EVAL                       = 0x0000006B
	PRODUCT_EMBEDDED_E_EVAL                     = 0x0000006C
	PRODUCT_NANO_SERVER                         = 0x0000006D
	PRODUCT_CLOUD_STORAGE_SERVER                = 0x0000006E
	PRODUCT_CORE_CONNECTED                      = 0x0000006F
	PRODUCT_PROFESSIONAL_STUDENT                = 0x00000070
	PRODUCT_CORE_CONNECTED_N                    = 0x00000071
	PRODUCT_PROFESSIONAL_STUDENT_N              = 0x00000072
	PRODUCT_CORE_CONNECTED_SINGLELANGUAGE       = 0x00000073
	PRODUCT_CORE_CONNECTED_COUNTRYSPECIFIC      = 0x00000074
	PRODUCT_CONNECTED_CAR                       = 0x00000075
	PRODUCT_INDUSTRY_HANDHELD                   = 0x00000076
	PRODUCT_PPI_PRO                             = 0x00000077
	PRODUCT_ARM64_SERVER                        = 0x00000078
	PRODUCT_EDUCATION                           = 0x00000079
	PRODUCT_EDUCATION_N                         = 0x0000007A
	PRODUCT_IOTUAP                              = 0x0000007B
	PRODUCT_CLOUD_HOST_INFRASTRUCTURE_SERVER    = 0x0000007C
	PRODUCT_ENTERPRISE_S                        = 0x0000007D
	PRODUCT_ENTERPRISE_S_N                      = 0x0000007E
	PRODUCT_PROFESSIONAL_S                      = 0x0000007F
	PRODUCT_PROFESSIONAL_S_N                    = 0x00000080
	PRODUCT_ENTERPRISE_S_EVALUATION             = 0x00000081
	PRODUCT_ENTERPRISE_S_N_EVALUATION           = 0x00000082
	PRODUCT_HOLOGRAPHIC                         = 0x00000087
	PRODUCT_PRO_SINGLE_LANGUAGE                 = 0x0000008A
	PRODUCT_PRO_CHINA                           = 0x0000008B
	PRODUCT_ENTERPRISE_SUBSCRIPTION             = 0x0000008C
	PRODUCT_ENTERPRISE_SUBSCRIPTION_N           = 0x0000008D
	PRODUCT_DATACENTER_NANO_SERVER              = 0x0000008F
	PRODUCT_STANDARD_NANO_SERVER                = 0x00000090
	PRODUCT_DATACENTER_A_SERVER_CORE            = 0x00000091
	PRODUCT_STANDARD_A_SERVER_CORE              = 0x00000092
	PRODUCT_DATACENTER_WS_SERVER_CORE           = 0x00000093
	PRODUCT_STANDARD_WS_SERVER_CORE             = 0x00000094
	PRODUCT_UTILITY_VM                          = 0x00000095
	PRODUCT_DATACENTER_EVALUATION_SERVER_CORE   = 0x0000009F
	PRODUCT_STANDARD_EVALUATION_SERVER_CORE     = 0x000000A0
	PRODUCT_PRO_WORKSTATION                     = 0x000000A1
	PRODUCT_PRO_WORKSTATION_N                   = 0x000000A2
	PRODUCT_PRO_FOR_EDUCATION                   = 0x000000A4
	PRODUCT_PRO_FOR_EDUCATION_N                 = 0x000000A5
	PRODUCT_AZURE_SERVER_CORE                   = 0x000000A8
	PRODUCT_AZURE_NANO_SERVER                   = 0x000000A9
	PRODUCT_ENTERPRISEG                         = 0x000000AB
	PRODUCT_ENTERPRISEGN                        = 0x000000AC
	PRODUCT_SERVERRDSH                          = 0x000000AF
	PRODUCT_CLOUD                               = 0x000000B2
	PRODUCT_CLOUDN                              = 0x000000B3
	PRODUCT_HUBOS                               = 0x000000B4
	PRODUCT_ONECOREUPDATEOS                     = 0x000000B6
	PRODUCT_CLOUDE                              = 0x000000B7
	PRODUCT_ANDROMEDA                           = 0x000000B8
	PRODUCT_IOTOS                               = 0x000000B9
	PRODUCT_CLOUDEN                             = 0x000000BA
	PRODUCT_UNLICENSED                          = 0xABCDABCD
)

func OsIsCore() bool {
	versionInfo := windows.RtlGetVersion()
	if versionInfo.MajorVersion > 6 || (versionInfo.MajorVersion == 6 && versionInfo.MinorVersion >= 2) {
		k, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels`, registry.READ)
		if err != nil {
			return false
		}
		nanoServerInteger, _, err1 := k.GetIntegerValue("NanoServer")
		serverCoreInteger, _, err2 := k.GetIntegerValue("ServerCore")
		serverGuiInteger, _, err3 := k.GetIntegerValue("Server-Gui-Shell")
		nanoServer := nanoServerInteger == 1 && err1 == nil
		serverCore := serverCoreInteger == 1 && err2 == nil
		serverGui := serverGuiInteger == 1 && err3 == nil
		k.Close()
		return (nanoServer || serverCore) && !serverGui
	}

	switch versionInfo.ProductType {
	case PRODUCT_DATACENTER_SERVER_CORE, PRODUCT_STANDARD_SERVER_CORE, PRODUCT_ENTERPRISE_SERVER_CORE, PRODUCT_WEB_SERVER_CORE, PRODUCT_DATACENTER_SERVER_CORE_V, PRODUCT_STANDARD_SERVER_CORE_V, PRODUCT_ENTERPRISE_SERVER_CORE_V, PRODUCT_STORAGE_EXPRESS_SERVER_CORE, PRODUCT_STORAGE_STANDARD_SERVER_CORE, PRODUCT_STORAGE_WORKGROUP_SERVER_CORE, PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE, PRODUCT_DATACENTER_A_SERVER_CORE, PRODUCT_STANDARD_A_SERVER_CORE, PRODUCT_DATACENTER_WS_SERVER_CORE, PRODUCT_STANDARD_WS_SERVER_CORE, PRODUCT_DATACENTER_EVALUATION_SERVER_CORE, PRODUCT_STANDARD_EVALUATION_SERVER_CORE, PRODUCT_AZURE_SERVER_CORE, PRODUCT_NANO_SERVER, PRODUCT_DATACENTER_NANO_SERVER, PRODUCT_STANDARD_NANO_SERVER, PRODUCT_AZURE_NANO_SERVER:
		return true
	}
	return false
}

func OsName() string {
	versionInfo := windows.RtlGetVersion()
	winType := ""
	switch versionInfo.ProductType {
	case 3:
		winType = " Server"
	case 2:
		winType = " Controller"
	}
	if OsIsCore() {
		winType += " Core"
	}
	return fmt.Sprintf("Windows%s %d.%d.%d", winType, versionInfo.MajorVersion, versionInfo.MinorVersion, versionInfo.BuildNumber)
}
