
import { relative, resolve, win32 } from 'path';

import { readdirAsync, lstatAsync } from 'fs-extra-promise';

import { fixWindowsVersion } from '../util';

export interface INsisComposerOptions {

    // Basic.
    appName: string;
    companyName: string;
    description: string;
    version: string;
    copyright: string;

    // Compression.
    compression: 'zlib' | 'bzip2' | 'lzma';
    solid: boolean;

    languages: string[];

    // Output.
    output: string;

}

export class NsisComposer {

    public static DIVIDER = '################################################################################';

    protected fixedVersion: string;

    constructor(protected options: INsisComposerOptions) {

        if(!this.options.appName) {
            this.options.appName = 'NO_APPNAME';
        }

        if(!this.options.companyName) {
            this.options.companyName = 'NO_COMPANYNAME';
        }

        if(!this.options.description) {
            this.options.description = 'NO_DESCRIPTION';
        }

        if(!this.options.version) {
            this.options.version = 'NO_VERSION';
        }

        if(!this.options.copyright) {
            this.options.copyright = 'NO_COPYRIGHT';
        }

        this.options.compression = this.options.compression || 'lzma';
        this.options.solid = this.options.solid ? true : false;
        this.options.languages = this.options.languages && this.options.languages.length > 0 ? this.options.languages : [ 'English' ];

        this.fixedVersion = fixWindowsVersion(this.options.version);

    }

    public async make(): Promise<string> {

        return `
${ NsisComposer.DIVIDER }
#
# Generated by nsis-gen.
#
${ NsisComposer.DIVIDER }

${ NsisComposer.DIVIDER }
#
# General
#
${ NsisComposer.DIVIDER }

Name "${ this.options.appName }"
Caption "${ this.options.appName }"
BrandingText "${ this.options.appName } ${ this.fixedVersion }"
SetCompressor ${ this.options.solid ? '/SOLID' : '' } ${ this.options.compression }
OutFile "${ win32.normalize(resolve(this.options.output)) }"

InstallDir "$LOCALAPPDATA\\${ this.options.appName }"
InstallDirRegKey HKCU "Software\\${ this.options.appName }" "InstallDir"

RequestExecutionLevel user
XPStyle on

${ NsisComposer.DIVIDER }
#
# Modern UI
#
${ NsisComposer.DIVIDER }

!include "MUI2.nsh"

!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\\${ this.options.appName }"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "StartMenuFolder"

!define MUI_FINISHPAGE_RUN "$INSTDIR\\${ this.options.appName }.exe"

Var StartMenuFolder

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

${
    this.options.languages.map((language) => {
        return `!insertmacro MUI_LANGUAGE "${ language }"`;
    }).join('\n')
}

${
    this.options.languages.length > 1
    ? `!insertmacro MUI_RESERVEFILE_LANGDLL`
    : ''
}

${ NsisComposer.DIVIDER }
#
# Resources
#
${ NsisComposer.DIVIDER }

VIProductVersion "${ this.fixedVersion }"
VIAddVersionKey "ProductName" "${ this.options.appName }"
VIAddVersionKey "CompanyName" "${ this.options.companyName }"
VIAddVersionKey "FileDescription" "${ this.options.description }"
VIAddVersionKey "FileVersion" "${ this.fixedVersion }"
VIAddVersionKey "LegalCopyright" "${ this.options.copyright }"

${ NsisComposer.DIVIDER }
#
# Hooks
#
${ NsisComposer.DIVIDER }

Function .onInit

    ${
        this.options.languages.length > 1
        ? `!insertmacro MUI_LANGDLL_DISPLAY`
        : ''
    }

FunctionEnd

${ NsisComposer.DIVIDER }
#
# Install
#
${ NsisComposer.DIVIDER }

Section -Install

SetShellVarContext current
SetOverwrite ifnewer

WriteRegStr HKCU "Software\\${ this.options.appName }" "InstallDir" "$INSTDIR"

${ await this.makeInstallerFiles() }

!insertmacro MUI_STARTMENU_WRITE_BEGIN Application

    CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"
    CreateShortcut "$SMPROGRAMS\\$StartMenuFolder\\${ this.options.appName }.lnk" "$INSTDIR\\${ this.options.appName }.exe"
    CreateShortcut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"

!insertmacro MUI_STARTMENU_WRITE_END

  WriteUninstaller "$INSTDIR\\Uninstall.exe"

SectionEnd

${ NsisComposer.DIVIDER }
#
# Uninstall
#
${ NsisComposer.DIVIDER }

Section Uninstall

RMDir /r "$INSTDIR"

!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder

Delete "$SMPROGRAMS\\$StartMenuFolder\\${ this.options.appName }.lnk"
Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk"
RMDir "$SMPROGRAMS\\$StartMenuFolder"

DeleteRegKey HKCU "Software\\${ this.options.appName }"

SectionEnd
`;

    }

    protected async makeInstallerFiles(): Promise<string> {

        return `SetOutPath "$INSTDIR"
FILE /r .\\*.*`;

    }

}
