Unicode true

!include "MUI2.nsh"
!include "LogicLib.nsh"
!include "WinVer.nsh"
!include "x64.nsh"
!include "FileFunc.nsh"

!ifndef PRODUCT_VERSION
  !error "PRODUCT_VERSION is required."
!endif
!ifndef DISPLAY_VERSION
  !error "DISPLAY_VERSION is required."
!endif
!ifndef RELEASE_ID
  !error "RELEASE_ID is required."
!endif
!ifndef OUTPUT_FILE
  !error "OUTPUT_FILE is required."
!endif
!ifndef PAYLOAD_ROOT
  !error "PAYLOAD_ROOT is required."
!endif
!ifndef PAYLOAD_MANIFEST
  !error "PAYLOAD_MANIFEST is required."
!endif
!ifndef READINESS_SCRIPT
  !error "READINESS_SCRIPT is required."
!endif
!ifndef VC_REDIST_PATH
  !error "VC_REDIST_PATH is required."
!endif
!ifndef INSTALLER_ICON
  !error "INSTALLER_ICON is required."
!endif
!ifndef PAYLOAD_SIZE_KB
  !error "PAYLOAD_SIZE_KB is required."
!endif

!define PRODUCT_NAME "HyperTwist"
!define PRODUCT_CHANNEL "Alpha"
!define PRODUCT_PUBLISHER "HyperTwist"
!define PRODUCT_WEBSITE "https://hypertwist.app"
!define PRODUCT_SUPPORT "https://hypertwist.app/support"
!define PRODUCT_REG_KEY "Software\HyperTwist\HyperTwist"
!define PRODUCT_UNINSTALL_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\HyperTwist"
!define INSTALL_MARKER "HyperTwist.install-marker"

Name "${PRODUCT_NAME} ${PRODUCT_CHANNEL}"
Caption "${PRODUCT_NAME} ${DISPLAY_VERSION} Setup"
BrandingText "${PRODUCT_NAME} | Explore dimensions beyond the ordinary"
OutFile "${OUTPUT_FILE}"
InstallDir "$PROGRAMFILES64\HyperTwist"
RequestExecutionLevel admin

CRCCheck force
SetDatablockOptimize on
SetCompressor /SOLID lzma
SetCompressorDictSize 64
ShowInstDetails show
ShowUninstDetails show
ManifestDPIAware true
ManifestSupportedOS all

Icon "${INSTALLER_ICON}"
UninstallIcon "${INSTALLER_ICON}"

VIProductVersion "${PRODUCT_VERSION}"
VIAddVersionKey /LANG=1033 "ProductName" "${PRODUCT_NAME}"
VIAddVersionKey /LANG=1033 "ProductVersion" "${DISPLAY_VERSION}"
VIAddVersionKey /LANG=1033 "CompanyName" "${PRODUCT_PUBLISHER}"
VIAddVersionKey /LANG=1033 "FileDescription" "${PRODUCT_NAME} ${PRODUCT_CHANNEL} Installer"
VIAddVersionKey /LANG=1033 "FileVersion" "${PRODUCT_VERSION}"
VIAddVersionKey /LANG=1033 "LegalCopyright" "Copyright (c) HyperTwist"
VIAddVersionKey /LANG=1033 "OriginalFilename" "HyperTwist-Setup.exe"

!define MUI_ABORTWARNING
!define MUI_ICON "${INSTALLER_ICON}"
!define MUI_UNICON "${INSTALLER_ICON}"
!define MUI_FINISHPAGE_LINK "Visit hypertwist.app"
!define MUI_FINISHPAGE_LINK_LOCATION "${PRODUCT_WEBSITE}"

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

!insertmacro MUI_LANGUAGE "English"

Function .onInit
  SetRegView 64

  ${IfNot} ${RunningX64}
    MessageBox MB_OK|MB_ICONSTOP \
      "HyperTwist requires 64-bit Windows." \
      /SD IDOK
    SetErrorLevel 10
    Quit
  ${EndIf}

  ${IfNot} ${AtLeastWin10}
    MessageBox MB_OK|MB_ICONSTOP \
      "HyperTwist requires Windows 10 version 22H2 or Windows 11." \
      /SD IDOK
    SetErrorLevel 11
    Quit
  ${EndIf}

  ReadRegStr $1 HKLM "${PRODUCT_REG_KEY}" "InstallLocation"
  StrCmp $1 "" install_location_ready
  StrCpy $INSTDIR $1

install_location_ready:
  ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "CurrentBuildNumber"
  IntCmp $0 19045 windows_build_ok windows_build_too_old windows_build_ok

windows_build_too_old:
  MessageBox MB_OK|MB_ICONSTOP \
    "This Windows build is too old for the supported HyperTwist Alpha baseline. Update to Windows 10 22H2 or Windows 11 and try again." \
    /SD IDOK
  SetErrorLevel 12
  Quit

windows_build_ok:
FunctionEnd

Function CleanOwnedPayloadForUpgrade
  ReadRegStr $0 HKLM "${PRODUCT_REG_KEY}" "InstallLocation"
  StrCmp $0 $INSTDIR registry_owner_confirmed cleanup_done

registry_owner_confirmed:
  IfFileExists "$INSTDIR\Installer\${INSTALL_MARKER}" 0 cleanup_done

  DetailPrint "Removing the previous HyperTwist payload before upgrade."
  RMDir /r "$INSTDIR\Content"
  RMDir /r "$INSTDIR\Engine"
  RMDir /r "$INSTDIR\UnrealHyperTwist"
  RMDir /r "$INSTDIR\Installer"
  Delete "$INSTDIR\Manifest_DebugFiles_Win64.txt"
  Delete "$INSTDIR\Manifest_NonUFSFiles_Win64.txt"
  Delete "$INSTDIR\Manifest_UFSFiles_Win64.txt"
  Delete "$INSTDIR\UnrealHyperTwist.exe"
  Delete "$INSTDIR\Uninstall HyperTwist.exe"

cleanup_done:
FunctionEnd

Function AssertSafeInstallLocation
  ${GetFileName} "$INSTDIR" $0
  StrCmp $0 "HyperTwist" install_leaf_safe install_location_refused

install_leaf_safe:
  ReadRegStr $0 HKLM "${PRODUCT_REG_KEY}" "InstallLocation"
  StrCmp $0 $INSTDIR install_registry_owner_candidate install_unowned_scan

install_registry_owner_candidate:
  IfFileExists "$INSTDIR\Installer\${INSTALL_MARKER}" install_location_safe install_unowned_scan

install_unowned_scan:
  FindFirst $0 $1 "$INSTDIR\*"

install_unowned_scan_next:
  StrCmp $1 "" install_unowned_empty
  StrCmp $1 "." install_unowned_continue
  StrCmp $1 ".." install_unowned_continue
  FindClose $0
  MessageBox MB_OK|MB_ICONSTOP \
    "The selected HyperTwist folder is not empty and is not owned by an existing registered HyperTwist installation. Choose an empty folder named HyperTwist." \
    /SD IDOK
  SetErrorLevel 14
  Abort

install_unowned_continue:
  FindNext $0 $1
  Goto install_unowned_scan_next

install_unowned_empty:
  FindClose $0
  Goto install_location_safe

install_location_refused:
  MessageBox MB_OK|MB_ICONSTOP \
    "The installation folder itself must be named HyperTwist, for example C:\Program Files\HyperTwist or D:\Games\HyperTwist." \
    /SD IDOK
  SetErrorLevel 13
  Abort

install_location_safe:
FunctionEnd

Section -ValidateInstallLocation
  Call AssertSafeInstallLocation
SectionEnd

Section -MicrosoftRuntime
  SetOutPath "$PLUGINSDIR"
  File /oname=vc_redist.x64.exe "${VC_REDIST_PATH}"
  DetailPrint "Installing or repairing the Microsoft Visual C++ 2015-2022 x64 runtime."
  ExecWait '"$PLUGINSDIR\vc_redist.x64.exe" /install /quiet /norestart' $0

  ${If} $0 == 3010
    DetailPrint "The Microsoft runtime requested a restart."
    SetRebootFlag true
  ${ElseIf} $0 == 1638
    DetailPrint "A compatible or newer Microsoft runtime is already installed."
  ${ElseIf} $0 != 0
    MessageBox MB_OK|MB_ICONSTOP \
      "Microsoft Visual C++ runtime setup failed with exit code $0. HyperTwist was not installed." \
      /SD IDOK
    SetErrorLevel 20
    Abort
  ${EndIf}
SectionEnd

Section "!HyperTwist application" SEC_CORE
  SectionIn RO
  AddSize ${PAYLOAD_SIZE_KB}

  ; Do not disturb a working prior install until every bundled prerequisite succeeds.
  Call CleanOwnedPayloadForUpgrade

  SetOutPath "$INSTDIR"
  File /r \
    /x "*.pdb" \
    /x "Manifest_DebugFiles_Win64.txt" \
    "${PAYLOAD_ROOT}\*"

  SetOutPath "$INSTDIR\Installer"
  File /oname=payload-manifest.json "${PAYLOAD_MANIFEST}"
  File /oname=Test-HyperTwistWindowsReadiness.ps1 "${READINESS_SCRIPT}"

  FileOpen $0 "$INSTDIR\Installer\${INSTALL_MARKER}" w
  FileWrite $0 "product=HyperTwist$\r$\n"
  FileWrite $0 "release=${RELEASE_ID}$\r$\n"
  FileWrite $0 "version=${DISPLAY_VERSION}$\r$\n"
  FileClose $0

  WriteUninstaller "$INSTDIR\Uninstall HyperTwist.exe"

  WriteRegStr HKLM "${PRODUCT_REG_KEY}" "InstallLocation" "$INSTDIR"
  WriteRegStr HKLM "${PRODUCT_REG_KEY}" "ReleaseId" "${RELEASE_ID}"
  WriteRegStr HKLM "${PRODUCT_REG_KEY}" "DisplayVersion" "${DISPLAY_VERSION}"

  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "DisplayName" "${PRODUCT_NAME} ${PRODUCT_CHANNEL}"
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "DisplayVersion" "${DISPLAY_VERSION}"
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "InstallLocation" "$INSTDIR"
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\UnrealHyperTwist.exe,0"
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "URLInfoAbout" "${PRODUCT_WEBSITE}"
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "HelpLink" "${PRODUCT_SUPPORT}"
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "UninstallString" "$\"$INSTDIR\Uninstall HyperTwist.exe$\""
  WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "QuietUninstallString" "$\"$INSTDIR\Uninstall HyperTwist.exe$\" /S"
  WriteRegDWORD HKLM "${PRODUCT_UNINSTALL_KEY}" "EstimatedSize" ${PAYLOAD_SIZE_KB}
  WriteRegDWORD HKLM "${PRODUCT_UNINSTALL_KEY}" "NoModify" 1
  WriteRegDWORD HKLM "${PRODUCT_UNINSTALL_KEY}" "NoRepair" 1

  SetShellVarContext all
  CreateDirectory "$SMPROGRAMS\HyperTwist"
  CreateShortCut "$SMPROGRAMS\HyperTwist\HyperTwist.lnk" \
    "$INSTDIR\UnrealHyperTwist.exe" "" "$INSTDIR\UnrealHyperTwist.exe" 0
  CreateShortCut "$SMPROGRAMS\HyperTwist\System Readiness Report.lnk" \
    "$SYSDIR\WindowsPowerShell\v1.0\powershell.exe" \
    "-NoProfile -ExecutionPolicy Bypass -File $\"$INSTDIR\Installer\Test-HyperTwistWindowsReadiness.ps1$\" -PayloadRoot $\"$INSTDIR$\" -TargetInstallRoot $\"$INSTDIR$\" -ExpectedPayloadManifestPath $\"$INSTDIR\Installer\payload-manifest.json$\" -WaitForUser" \
    "$INSTDIR\UnrealHyperTwist.exe" 0
  CreateShortCut "$SMPROGRAMS\HyperTwist\Uninstall HyperTwist.lnk" \
    "$INSTDIR\Uninstall HyperTwist.exe"
SectionEnd

Section "Desktop shortcut" SEC_DESKTOP
  SetShellVarContext all
  CreateShortCut "$DESKTOP\HyperTwist.lnk" \
    "$INSTDIR\UnrealHyperTwist.exe" "" "$INSTDIR\UnrealHyperTwist.exe" 0
SectionEnd

LangString DESC_SEC_CORE ${LANG_ENGLISH} \
  "The complete HyperTwist desktop Alpha, puzzle runtimes, learning studio, browser shell, and local solver data."
LangString DESC_SEC_DESKTOP ${LANG_ENGLISH} \
  "Create an all-users HyperTwist shortcut on the desktop."

!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
  !insertmacro MUI_DESCRIPTION_TEXT ${SEC_CORE} $(DESC_SEC_CORE)
  !insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} $(DESC_SEC_DESKTOP)
!insertmacro MUI_FUNCTION_DESCRIPTION_END

Section "Uninstall"
  SetRegView 64
  ${GetFileName} "$INSTDIR" $1
  StrCmp $1 "HyperTwist" uninstall_leaf_safe uninstall_refused

uninstall_leaf_safe:
  ReadRegStr $0 HKLM "${PRODUCT_REG_KEY}" "InstallLocation"
  StrCmp $0 $INSTDIR uninstall_registry_owned uninstall_refused

uninstall_registry_owned:
  IfFileExists "$INSTDIR\Installer\${INSTALL_MARKER}" uninstall_owned uninstall_refused

uninstall_refused:
  MessageBox MB_OK|MB_ICONSTOP \
    "HyperTwist registry ownership or the install marker is missing. The uninstaller will not delete an unverified directory." \
    /SD IDOK
  SetErrorLevel 30
  Abort

uninstall_owned:
  SetShellVarContext all
  Delete "$DESKTOP\HyperTwist.lnk"
  RMDir /r "$SMPROGRAMS\HyperTwist"

  DeleteRegKey HKLM "${PRODUCT_UNINSTALL_KEY}"
  DeleteRegKey HKLM "${PRODUCT_REG_KEY}"
  DeleteRegKey /ifempty HKLM "Software\HyperTwist"

  RMDir /r "$INSTDIR\Content"
  RMDir /r "$INSTDIR\Engine"
  RMDir /r "$INSTDIR\UnrealHyperTwist"
  Delete "$INSTDIR\Manifest_DebugFiles_Win64.txt"
  Delete "$INSTDIR\Manifest_NonUFSFiles_Win64.txt"
  Delete "$INSTDIR\Manifest_UFSFiles_Win64.txt"
  Delete "$INSTDIR\UnrealHyperTwist.exe"
  Delete "$INSTDIR\Installer\payload-manifest.json"
  Delete "$INSTDIR\Installer\Test-HyperTwistWindowsReadiness.ps1"
  Delete "$INSTDIR\Installer\${INSTALL_MARKER}"
  RMDir "$INSTDIR\Installer"
  Delete "$INSTDIR\Uninstall HyperTwist.exe"
  RMDir "$INSTDIR"
SectionEnd
