name: build

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  CARGO_TERM_COLOR: always
  RUST_MIN_STACK: 16777212

permissions: {}

jobs:
  build:
    strategy:
      matrix:
        platform: [ubuntu-24.04, macos-15, windows-latest]
        include:
          - platform: ubuntu-24.04
            artifact-path: target/release/fend
            artifact-platform-name: linux-x86_64-gnu
            env-command: ">> $GITHUB_ENV"
          - platform: macos-15
            artifact-path: target/release/fend
            artifact-platform-name: macos-aarch64
            env-command: ">> $GITHUB_ENV"
          - platform: windows-latest
            artifact-path: target/release/fend.exe
            artifact-platform-name: windows-x64-exe
            env-command: "| Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append"

    permissions:
      contents: read

    runs-on: ${{ matrix.platform }}

    timeout-minutes: 20

    steps:
      - uses: actions/checkout@v4

      - name: Update Rust
        run: rustup update

      - uses: swatinem/rust-cache@v2

      - name: Clippy, rustfmt
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: |
          rustup component add clippy
          cargo clippy --workspace --all-targets --all-features -- -D warnings
          cargo fmt -- --check

      - name: Compile icon/resources.res
        if: ${{ matrix.platform == 'windows-latest' }}
        run: |
          $InstallationPath = vswhere -products * -latest -prerelease -property installationPath
          pushd "$($InstallationPath)\VC\Auxiliary\Build"
          cmd /c "vcvarsall.bat x64 & set" |
          foreach {
            if ($_ -match "=") {
              $v = $_.split("=", 2); set-item -force -path "ENV:\$($v[0])" -value "$($v[1])"
            }
          }
          popd
          .\icon\create-resources.ps1

      - name: Build, get version
        run: |
          cargo run --release --no-default-features --features rustls --package fend -- help
          echo "FEND_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages | .[0].version')" ${{ matrix.env-command }}

        # Only run unit tests on non-Linux platforms since Linux runs
        # them as part of code coverage testing
      - name: Test
        if: ${{ matrix.platform != 'ubuntu-24.04' }}
        run: |
          cargo test --workspace -- --nocapture --quiet

      - name: Test (Linux i686)
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: |
          sudo apt-get update -y
          sudo apt-get install -yq gcc-i686-linux-gnu
          rustup target add i686-unknown-linux-gnu
          export CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=/usr/bin/i686-linux-gnu-gcc
          LD_LIBRARY_PATH=/usr/i686-linux-gnu/lib/ cargo test \
            --target i686-unknown-linux-gnu --no-default-features --features rustls --workspace -- --nocapture --quiet

      - name: Generate code coverage
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        continue-on-error: true
        run: |
          RUSTFLAGS="-C instrument-coverage" \
            cargo test --workspace -- --quiet
          wget https://apt.llvm.org/llvm.sh
          chmod +x llvm.sh
          LLVM_VERSION="$(rustc -vV | sed -n 's/LLVM version: //p' | grep -o '^[^.]\+')"
          echo "rustc llvm version: $LLVM_VERSION"
          sudo ./llvm.sh "$LLVM_VERSION"
          rm llvm.sh
          "llvm-profdata-$LLVM_VERSION" merge -sparse */*.profraw -o fend.profdata
          "llvm-cov-$LLVM_VERSION" report \
            --use-color \
            --ignore-filename-regex='/.cargo/registry' \
            --ignore-filename-regex='/rustc' \
            --instr-profile=fend.profdata \
            $( \
              for file in \
                $( \
                  RUSTFLAGS="-C instrument-coverage" \
                    cargo test --workspace --no-run --message-format=json \
                      | jq -r "select(.profile.test == true) | .filenames[]" \
                      | grep -v dSYM - \
                ); \
              do \
                printf "%s %s " -object $file; \
              done \
            )
          "llvm-cov-$LLVM_VERSION" export \
            --ignore-filename-regex='/.cargo/registry' \
            --ignore-filename-regex='/rustc' \
            --format='lcov' \
            --instr-profile=fend.profdata \
            $( \
              for file in \
                $( \
                  RUSTFLAGS="-C instrument-coverage" \
                    cargo test --workspace --no-run --message-format=json \
                      | jq -r "select(.profile.test == true) | .filenames[]" \
                      | grep -v dSYM - \
                ); \
              do \
                printf "%s %s " -object $file; \
              done \
            ) >coverage.txt

      - name: Upload to codecov.io
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: false

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: fend-${{ env.FEND_VERSION }}-${{ matrix.artifact-platform-name }}
          path: ${{ matrix.artifact-path }}
          if-no-files-found: error

      - name: Build (linux-armv7-gnueabihf)
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: |
          rustup target add armv7-unknown-linux-gnueabihf
          sudo apt-get install -yq gcc-arm-linux-gnueabihf
          export CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=/usr/bin/arm-linux-gnueabihf-gcc
          cargo build --release --package fend --no-default-features --features rustls --target armv7-unknown-linux-gnueabihf

      - name: Upload artifacts (linux-armv7-gnueabihf)
        uses: actions/upload-artifact@v4
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        with:
          name: fend-${{ env.FEND_VERSION }}-linux-armv7-gnueabihf
          path: target/armv7-unknown-linux-gnueabihf/release/fend
          if-no-files-found: error

      - name: Build (linux-aarch64-gnu)
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: |
          rustup target add aarch64-unknown-linux-gnu
          sudo apt-get install -yq gcc-aarch64-linux-gnu
          export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=/usr/bin/aarch64-linux-gnu-gcc
          cargo build --release --package fend --no-default-features --features rustls --target aarch64-unknown-linux-gnu

      - name: Upload artifacts (linux-aarch64-gnu)
        uses: actions/upload-artifact@v4
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        with:
          name: fend-${{ env.FEND_VERSION }}-linux-aarch64-gnu
          path: target/aarch64-unknown-linux-gnu/release/fend
          if-no-files-found: error

      - name: Build (linux-x86_64-musl)
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: |
          rustup target add x86_64-unknown-linux-musl
          sudo apt-get install -yq musl-tools
          cargo build --release --package fend --no-default-features --features rustls --target x86_64-unknown-linux-musl

      - name: Upload artifacts (linux-x86_64-musl)
        uses: actions/upload-artifact@v4
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        with:
          name: fend-${{ env.FEND_VERSION }}-linux-x86_64-musl
          path: target/x86_64-unknown-linux-musl/release/fend
          if-no-files-found: error

      - name: Set up Homebrew
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH

      - name: Build fend-wasm
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: |
          brew install pandoc
          curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
          sudo apt-get install -yq imagemagick
          ./web/build.sh

      - name: Upload GitHub Pages artifact
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        uses: actions/upload-pages-artifact@v3
        with:
          path: web/dist

      - name: Build man page
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        run: |
          ./documentation/build.sh

      - name: Upload man page
        if: ${{ matrix.platform == 'ubuntu-24.04' }}
        uses: actions/upload-artifact@v4
        with:
          name: man-page
          path: documentation/fend.1
          if-no-files-found: error

      - name: Build MSIX installer
        if: ${{ github.ref == 'refs/heads/main' && matrix.platform == 'windows-latest' }}
        run: |
          .\windows-msix\build.ps1
        env:
          WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}

      - name: Upload artifacts (MSIX)
        uses: actions/upload-artifact@v4
        if: ${{ github.ref == 'refs/heads/main' && matrix.platform == 'windows-latest' }}
        with:
          name: fend-${{ env.FEND_VERSION }}-windows-x64-msix
          path: windows-msix/fend-windows-x64.msix
          if-no-files-found: error

      - name: Build MSI installer
        if: ${{ matrix.platform == 'windows-latest' }}
        run: |
          .\windows-wix\build.ps1

      - name: Upload artifacts (MSI)
        uses: actions/upload-artifact@v4
        if: ${{ matrix.platform == 'windows-latest' }}
        with:
          name: fend-${{ env.FEND_VERSION }}-windows-x64-msi
          path: windows-wix/build/fend-windows-x64.msi
          if-no-files-found: error

      - name: Build telegram bot
        if: ${{ github.ref == 'refs/heads/main' && matrix.platform == 'ubuntu-24.04' }}
        run: |
          ./telegram-bot/build.sh

      - name: Upload artifacts (telegram bot)
        uses: actions/upload-artifact@v4
        if: ${{ github.ref == 'refs/heads/main' && matrix.platform == 'ubuntu-24.04' }}
        with:
          name: lambda_package
          path: telegram-bot/lambda_package.zip
          if-no-files-found: error

  deploy_telegram:
    runs-on: ubuntu-24.04
    needs: [build]
    if: ${{ github.ref == 'refs/heads/main' }}

    permissions:
      actions: read
      contents: read
      id-token: write

    environment:
      name: telegram-bot
      url: https://t.me/fend_calc_bot

    steps:
      - uses: actions/checkout@v4

      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: lambda_package
          path: telegram-bot/

      - name: Get AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: us-east-1
          role-to-assume: ${{ secrets.ROLE_TO_ASSUME_ARN }}
          role-duration-seconds: 900
          mask-aws-account-id: true

      - name: Deploy Telegram Bot
        run: |
          TELEGRAM_BOT_API_TOKEN=${{ secrets.TELEGRAM_BOT_API_TOKEN }} \
            ./telegram-bot/deploy.sh

  deploy_website:
    runs-on: ubuntu-24.04
    needs: [build]
    if: ${{ github.ref == 'refs/heads/main' }}

    permissions:
      actions: read
      pages: write
      id-token: write

    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
