name: Build - Windows

on:
  workflow_call:
    inputs:
      NIGHTLY:
        default: false
        type: boolean

jobs:
  build:
    name: Build
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [windows-2019]
        arch: ["Win32", "Win64"]
    env:
      GH_TOKEN: ${{ github.token }}
      OPENSSL_VERSION: 1.1.1.2100
      QT_VERSION: 5.15.2
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install OpenSSL
        run: |
          if ("${{ matrix.arch }}" -eq "Win32") {
            choco install openssl --x86 --version=${{ env.OPENSSL_VERSION}}
          } else {
            choco install openssl --version=${{ env.OPENSSL_VERSION}}
          }

      - name: Install Ninja (Windows)
        run: choco install -y --no-progress ninja

      # When building SQLCipher, if we specify a path to OpenSSL and
      # there are spaces in the path, an error will occur, so to
      # avoid this, create the symlink.
      - name: Create OpenSSL symlink
        run: |
          mkdir C:\dev
          if ("${{ matrix.arch }}" -eq "Win32") {
            New-Item -Path "C:\dev\OpenSSL-${{ matrix.arch }}" -ItemType SymbolicLink -Value "C:\Program Files (x86)\OpenSSL-Win32\"
          } else {
            New-Item -Path "C:\dev\OpenSSL-${{ matrix.arch }}" -ItemType SymbolicLink -Value "C:\Program Files\OpenSSL"
          }

      - name: Install Qt
        uses: jurplel/install-qt-action@v3
        with:
          arch: ${{ matrix.arch == 'Win32' && 'win32_msvc2019' || matrix.arch == 'Win64' && 'win64_msvc2019_64'}}
          cache: true
          cache-key-prefix: "cache"
          version: ${{ env.QT_VERSION }}

      - name: Download 'nalgeon/sqlean'
        run: |
          if ("${{ matrix.arch }}" -eq "Win32") {
            gh release download --pattern "sqlean-win-x86.zip" --repo "nalgeon/sqlean"
            Expand-Archive -Path sqlean-win-x86.zip -DestinationPath .\sqlean
          } else {
            gh release download --pattern "sqlean-win-x64.zip" --repo "nalgeon/sqlean"
            Expand-Archive -Path sqlean-win-x64.zip -DestinationPath .\sqlean
          }

      - name: Setup MSVC
        uses: ilammy/msvc-dev-cmd@v1
        with:
          arch: ${{ matrix.arch == 'Win32' && 'amd64_x86' || matrix.arch == 'Win64' && 'amd64'}}

      - name: Install SQLite
        run: |
          $htmlContent = Invoke-WebRequest -Uri "https://sqlite.org/download.html" | Select-Object -ExpandProperty Content
          $regex = [regex]::new('PRODUCT,(\d+\.\d+\.\d+),(\d+/sqlite-amalgamation-\d+\.zip),\d+,(.+)')
          $match = $regex.Match($htmlContent)
          $relativeUrl = $match.Groups[2].Value
          $downloadLink = "https://sqlite.org/$relativeUrl"
          Invoke-WebRequest -Uri $downloadLink -OutFile 'sqlite.zip'
          Expand-Archive -Path sqlite.zip -DestinationPath C:\dev\
          Move-Item -Path C:\dev\sqlite-amalgamation-* C:\dev\SQLite-${{ matrix.arch }}
          cd C:\dev\SQLite-${{ matrix.arch }}
          cl sqlite3.c -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_STAT4 -DSQLITE_SOUNDEX -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_GEOPOLY -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_MAX_ATTACHED=125 -DSQLITE_API="__declspec(dllexport)" -link -dll -out:sqlite3.dll

      - name: Install SQLite Extensions
        run: |
          cp .\src\extensions\extension-formats.c C:\dev\SQLite-${{ matrix.arch}}\
          cp .\src\extensions\extension-formats.def C:\dev\SQLite-${{ matrix.arch}}\
          cp .\src\extensions\extension-functions.c C:\dev\SQLite-${{ matrix.arch}}\
          cp .\src\extensions\extension-functions.def C:\dev\SQLite-${{ matrix.arch}}\
          cd C:\dev\SQLite-${{ matrix.arch}}\
          cl /MD extension-formats.c -link -dll -def:extension-formats.def -out:formats.dll
          cl /MD extension-functions.c -link -dll -def:extension-functions.def -out:math.dll
          # FIXME: Disable building the 'fileio' extension for now (#3488)
          # If this issue is resolved, be sure to delete the related patch for WiX
          # curl -L -o fileio.c "https://sqlite.org/src/raw?filename=ext/misc/fileio.c&ci=trunk"
          # curl -L -o test_windirent.c "https://sqlite.org/src/raw?filename=src/test_windirent.c&ci=trunk"
          # curl -L -o test_windirent.h "https://sqlite.org/src/raw?filename=src/test_windirent.h&ci=trunk"
          # cl /MD fileio.c test_windirent.c -link sqlite3.lib -dll -out:fileio.dll

      - name: Install SQLCipher
        run: |
          cd C:\dev
          git clone https://github.com/sqlcipher/sqlcipher
          mv sqlcipher SQLCipher-${{ matrix.arch }}
          cd SQLCipher-${{ matrix.arch }}
          git switch $(git describe --tags --abbrev=0)
          nmake /f Makefile.msc sqlcipher.dll USE_AMALGAMATION=1 NO_TCL=1 SQLITE3DLL=sqlcipher.dll SQLITE3LIB=sqlcipher.lib SQLITE3EXE=sqlcipher.exe LTLINKOPTS="C:\dev\OpenSSL-${{ matrix.arch }}\lib\libcrypto.lib" OPT_FEATURE_FLAGS="-DSQLITE_TEMP_STORE=2 -DSQLITE_HAS_CODEC=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_STAT4=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_RTREE=1 -DSQLCIPHER_CRYPTO_OPENSSL=1 -DSQLITE_MAX_ATTACHED=125 -IC:\dev\OpenSSL-${{ matrix.arch }}\include"
          mkdir sqlcipher
          copy sqlite3.h sqlcipher

      - name: Patch WiX Toolset Variables
        run: |
          git apply .github\patch\product.wxs.patch
          git apply .github\patch\translations.wxs.patch
          git apply .github\patch\variables.wxi.patch

      - name: Configure build (SQLite)
        run: |
          mkdir release-sqlite && cd release-sqlite
          if ("${{ matrix.arch }}" -eq "Win32") {
            cmake -G"Ninja Multi-Config" -DCMAKE_PREFIX_PATH="C:/dev/SQLite-Win32;C:/dev/OpenSSL-Win32" ..\
          } else {
            cmake -G"Ninja Multi-Config" -DCMAKE_PREFIX_PATH="C:/dev/SQLite-Win64;C:/dev/OpenSSL-Win64" ..\
          }

      - name: Build (SQLite)
        run: |
          cd release-sqlite
          cmake --build . --config Release

      - name: Configure build (SQLCipher)
        run: |
          mkdir release-sqlcipher && cd release-sqlcipher
          if ("${{ matrix.arch }}" -eq "Win32") {
            cmake -G"Ninja Multi-Config" -Dsqlcipher=1 -DCMAKE_PREFIX_PATH="C:/dev/SQLCipher-Win32;C:/dev/OpenSSL-Win32" ..\
          } else {
            cmake -G"Ninja Multi-Config" -Dsqlcipher=1 -DCMAKE_PREFIX_PATH="C:/dev/SQLCipher-Win64;C:/dev/OpenSSL-Win64" ..\
          }

      - name: Build (SQLCipher)
        run: |
          cd release-sqlcipher
          cmake --build . --config Release

      - if: github.event_name != 'pull_request'
        name: Create MSI
        env:
          ExePath: ${{ github.workspace }}
          OpenSSLPath: C:\dev\OpenSSL-${{ matrix.arch }}
          SQLCipherPath: C:\dev\SQLCipher-${{ matrix.arch }}
          SqleanPath: ${{ github.workspace }}\sqlean
          SQLitePath: C:\dev\SQLite-${{ matrix.arch }}
        run: |
          cd installer/windows
          ./build.cmd "${{ matrix.arch }}".ToLower()
          $ARCH="${{ matrix.arch }}".ToLower()
          $DATE=$(Get-Date -Format "yyyy-MM-dd")
          if ("${{ inputs.NIGHTLY }}" -eq "true") {
            mv DB.Browser.for.SQLite-*.msi "DB.Browser.for.SQLite-$DATE-$ARCH.msi"
          } else {
            mv DB.Browser.for.SQLite-*.msi "DB.Browser.for.SQLite-dev-$(git rev-parse --short HEAD)-$ARCH.msi"
          }

      - if: github.event_name != 'pull_request'
        name: Upload artifacts for code signing with SignPath
        id: unsigned-artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-artifacts-${{ matrix.os}}-${{ matrix.arch }}-unsigned
          path: installer\windows\DB.Browser.for.SQLite-*.msi

      # Change the signing-policy-slug when you release an RC, RTM or stable release.
      - if: github.event_name != 'pull_request'
        name: Code signing with SignPath
        uses: signpath/github-action-submit-signing-request@v1
        with:
          api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
          github-artifact-id: '${{ steps.unsigned-artifacts.outputs.artifact-id }}'
          organization-id: '${{ secrets.SIGNPATH_ORGANIZATION_ID }}'
          output-artifact-directory: .\installer\windows
          project-slug: 'sqlitebrowser'
          signing-policy-slug: 'test-signing'
          wait-for-completion: true

      - if: github.event_name != 'pull_request'
        name: Create ZIP
        run: |
          $ARCH="${{ matrix.arch }}".ToLower()
          $DATE=$(Get-Date -Format "yyyy-MM-dd")
          if ("${{ inputs.NIGHTLY }}" -eq "true") {
            $FILENAME_FORMAT="DB.Browser.for.SQLite-$DATE-$ARCH.zip"
          } else {
            $FILENAME_FORMAT="DB.Browser.for.SQLite-dev-$(git rev-parse --short HEAD)-$ARCH.zip"
          }
          Start-Process msiexec.exe -ArgumentList "/a $(dir installer\windows\DB.Browser.for.SQLite-*.msi) /q TARGETDIR=$PWD\target\" -Wait
          if ("${{ matrix.arch }}" -eq "Win32") {
            move target\System\* "target\DB Browser for SQLite\"
          } else {
            move target\System64\* "target\DB Browser for SQLite\"
          }
          Compress-Archive -Path "target\DB Browser for SQLite\*" -DestinationPath $FILENAME_FORMAT

      - if: github.event_name != 'pull_request'
        name: Prepare artifacts
        run: |
          mkdir build-artifacts
          move installer\windows\DB.Browser.for.SQLite-*.msi build-artifacts\
          move DB.Browser.for.SQLite-*.zip build-artifacts\
          Compress-Archive -Path build-artifacts\* -DestinationPath build-artifacts-${{ matrix.arch }}.zip

      - if: github.event_name != 'pull_request'
        name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-artifacts-${{ matrix.os }}-${{ matrix.arch }}
          path: build-artifacts-${{ matrix.arch }}.zip
