# Terms:
# "build" - Compile web project using webpack.
# "package" - Produce a distributive package for a specific platform as a workflow artifact.
# "publish" - Send a package to corresponding store and GitHub release page.
# "release" - build + package + publish
#
# Jobs in this workflow will skip the "publish" step when `SHOULD_PUBLISH` is not set.

name: Package and publish

on:
  workflow_dispatch:
    inputs:
      forceRelease:
        description: 'Force production build'
        required: false
        default: false
        type: boolean
  push:
    branches:
      - master

env:
  IS_ON_MASTER: ${{ github.ref == 'refs/heads/master' }}
  SHOULD_PUBLISH: ${{ github.ref == 'refs/heads/master' && vars.PUBLISH_REPO || '' }}
  PUBLISH_REPO: ${{ vars.PUBLISH_REPO }}
  GH_TOKEN: ${{ secrets.GH_TOKEN }}
  UPDATER_GIST_URL: ${{ secrets.UPDATER_GIST_URL }}
  UPDATER_GIST_ID: ${{ secrets.UPDATER_GIST_ID }}

jobs:
  get-version:
    runs-on: ubuntu-latest
    outputs:
      package-version: ${{ steps.extract-version.outputs.package-version }}
      tag-name: ${{ steps.extract-version.outputs.tag-name }}
      should-publish: ${{ steps.extract-version.outputs.should-publish }}
      release-name: ${{ steps.extract-version.outputs.release-name }}
    steps:
      - uses: actions/checkout@v6

      - name: Extract version and tag
        id: extract-version
        run: |
          PACKAGE_VERSION=$(grep -m1 '^version' tauri/Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
          TAG_NAME="air_v${PACKAGE_VERSION}"
          RELEASE_NAME="Telegram Air v${PACKAGE_VERSION}"
          echo "package-version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
          echo "tag-name=$TAG_NAME" >> $GITHUB_OUTPUT
          echo "release-name=$RELEASE_NAME" >> $GITHUB_OUTPUT
          echo "should-publish=$SHOULD_PUBLISH" >> $GITHUB_OUTPUT
          echo "Extracted version: $PACKAGE_VERSION"
          echo "Generated tag: $TAG_NAME"
          echo "Generated release name: $RELEASE_NAME"

  check-version:
    runs-on: ubuntu-latest
    needs: get-version
    outputs:
      should-skip: ${{ steps.check-release.outputs.should-skip }}
    steps:
      - name: Check if release already exists
        id: check-release
        env:
          PACKAGE_VERSION: ${{ needs.get-version.outputs.package-version }}
          TAG_NAME: ${{ needs.get-version.outputs.tag-name }}
        run: |
          # For non-master branches or when publishing is disabled, always continue
          if [ -z "$SHOULD_PUBLISH" ]; then
            echo "🚧 Publishing disabled (non-master branch or PUBLISH_REPO not set)"
            echo "should-skip=false" >> $GITHUB_OUTPUT
            exit 0
          fi

          echo "Checking if release already exists for tag: $TAG_NAME"

          RESPONSE=$(curl -s -H "Authorization: token $GH_TOKEN" \
            "https://api.github.com/repos/$PUBLISH_REPO/releases/tags/$TAG_NAME")

          if echo "$RESPONSE" | jq -e '.tag_name' > /dev/null; then
            IS_DRAFT=$(echo "$RESPONSE" | jq -r '.draft')
            if [ "$IS_DRAFT" = "false" ]; then
              echo "✅ Published release already exists for version $PACKAGE_VERSION"
              echo "should-skip=true" >> $GITHUB_OUTPUT
            else
              echo "📝 Draft release exists for version $PACKAGE_VERSION, will continue"
              echo "should-skip=false" >> $GITHUB_OUTPUT
            fi
          else
            echo "🆕 No release found for version $PACKAGE_VERSION, will create new release"
            echo "should-skip=false" >> $GITHUB_OUTPUT
          fi

  create-release:
    runs-on: ubuntu-latest
    needs: [get-version, check-version]
    if: needs.get-version.outputs.should-publish != '' && needs.check-version.outputs.should-skip != 'true'
    outputs:
      releaseId: ${{ steps.create-release.outputs.releaseId }}
    steps:
      - name: Create draft release
        id: create-release
        env:
          PACKAGE_VERSION: ${{ needs.get-version.outputs.package-version }}
          TAG_NAME: ${{ needs.get-version.outputs.tag-name }}
          RELEASE_NAME: ${{ needs.get-version.outputs.release-name }}
        run: |
          echo "Creating draft release for tag: $TAG_NAME"
          echo "Repository: $PUBLISH_REPO"
          RESPONSE=$(curl -X POST \
            -H "Authorization: token $GH_TOKEN" \
            -d '{"tag_name": "'"$TAG_NAME"'", "name": "'"$RELEASE_NAME"'", "draft": true}' \
            "https://api.github.com/repos/$PUBLISH_REPO/releases")
          RELEASE_ID=$(echo "$RESPONSE" | jq -r '.id')
          echo "Extracted Release ID: $RELEASE_ID"
          if [ "$RELEASE_ID" = "null" ]; then
            echo "Error: Failed to create release. Response was: $RESPONSE"
            exit 1
          fi
          echo "releaseId=$RELEASE_ID" >> $GITHUB_OUTPUT

  package-tauri:
    name: Build, package and publish Tauri
    needs: [get-version, check-version, create-release]
    if: ${{ always() && needs.check-version.outputs.should-skip != 'true' }}
    permissions:
      contents: write
    strategy:
      fail-fast: false
      matrix:
        settings:
          - platform: "macos-latest"
            args: "--target aarch64-apple-darwin"
          - platform: "macos-latest"
            args: "--target x86_64-apple-darwin"
          - platform: 'windows-latest'
            args: ''
    runs-on: ${{ matrix.settings.platform }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Set Xcode version
        if: matrix.settings.platform == 'macos-latest'
        uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: latest-stable

      - name: Setup Node.js ${{ vars.NODE_VERSION }}
        uses: actions/setup-node@v6
        with:
          node-version: ${{ vars.NODE_VERSION }}

      - name: Install Rust stable
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.settings.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}

      - name: Install Tauri dependencies (ubuntu only)
        if: matrix.settings.platform == 'ubuntu-22.04'
        run: |
          sudo apt-get update
          sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf

      - name: Cache node modules
        id: npm-cache
        uses: actions/cache@v5
        with:
          path: node_modules
          key: ${{ runner.os }}-build-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-

      - name: Install dependencies
        if: steps.npm-cache.outputs.cache-hit != 'true'
        run: npm ci

      - name: Extract repository owner and name
        id: repository-info
        if: needs.get-version.outputs.should-publish != ''
        shell: bash
        run: |
          echo "owner=${PUBLISH_REPO%%/*}" >> $GITHUB_OUTPUT
          echo "repo=${PUBLISH_REPO#*/}" >> $GITHUB_OUTPUT

      # Windows code signing setup
      - name: Setup certificate and environment variables (Windows)
        if: matrix.settings.platform == 'windows-latest'
        shell: bash
        run: |
          echo "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
          echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
          echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
          echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
          echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
          echo "KEYPAIR_ALIAS=${{ secrets.KEYPAIR_ALIAS }}" >> "$GITHUB_ENV"

      - name: Install DigiCert Client tools (Windows)
        if: matrix.settings.platform == 'windows-latest'
        uses: digicert/code-signing-software-trust-action@v1.2.0
        with:
          simple-signing-mode: true

      - name: Define Tauri configuration overrides
        id: config-overrides
        uses: actions/github-script@v8
        env:
          BASE_URL: ${{ vars.BASE_URL }}
          UPDATER_PUBLIC_KEY: ${{ secrets.UPDATER_PUBLIC_KEY }}
          WITH_UPDATER: ${{ needs.get-version.outputs.should-publish != '' && 'true' || 'false' }}
        with:
          script: |
            const workspacePath = process.env.GITHUB_WORKSPACE.replace(/\\/g, '/');
            const moduleUrl = `file:///${workspacePath}/deploy/prepareTauriConfig.js`;
            const { default: prepareTauriConfig } = await import(moduleUrl)
            const config = prepareTauriConfig();

            const configJson = JSON.stringify(config);
            console.log(configJson);

            core.setOutput("json", configJson);

      - name: Build, package and publish
        uses: tauri-apps/tauri-action@v0
        id: build-tauri
        env:
          APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
          APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
          APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
          BASE_URL: ${{ vars.BASE_URL }}
          TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.UPDATER_PRIVATE_KEY }}
          TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.UPDATER_PRIVATE_KEY_PASSWORD }}
          WITH_UPDATER: ${{ needs.get-version.outputs.should-publish != '' && 'true' || 'false' }}
        with:
          args: "-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}"
          includeDebug: ${{ needs.get-version.outputs.should-publish == '' && !inputs.forceRelease }}
          includeRelease: ${{ needs.get-version.outputs.should-publish != '' || inputs.forceRelease }}
          releaseId: ${{ needs.create-release.outputs.releaseId }}
          owner: ${{ steps.repository-info.outputs.owner }}
          repo: ${{ steps.repository-info.outputs.repo }}

      - name: Get file info
        id: file-info
        shell: bash
        run: |
          FULL_PATH=$(echo "${{ fromJSON(steps.build-tauri.outputs.artifactPaths)[0] }}")
          FILENAME=$(basename "$FULL_PATH")
          NAME="${FILENAME%.*}"
          FILE_PATH=$(readlink -f "$(dirname "$FULL_PATH")")
          ARCHITECTURE=$(echo "${{ matrix.settings.args }}" | grep -oE 'x86_64|aarch64' || echo "")
          echo "name=$NAME" >> $GITHUB_OUTPUT
          echo "filename=$FILENAME" >> $GITHUB_OUTPUT
          echo "architecture=$ARCHITECTURE" >> $GITHUB_OUTPUT
          echo "path=$FILE_PATH" >> $GITHUB_OUTPUT

      # MacOS release
      - name: Rebuild DMG with custom background (MacOS)
        if: matrix.settings.platform == 'macos-latest'
        run: |
          brew install create-dmg
          ./deploy/tauri_create_dmg.sh "${{ steps.file-info.outputs.path }}/${{ steps.file-info.outputs.name }}.dmg" "${{ steps.file-info.outputs.path }}/${{ steps.file-info.outputs.filename }}"

      - name: Upload release asset (MacOS)
        if: matrix.settings.platform == 'macos-latest' && needs.get-version.outputs.should-publish != ''
        shell: bash
        run: |
          SANITIZED_FILENAME=$(echo "${{ steps.file-info.outputs.name }}" | sed 's/ /./g')
          PUBLISH_FILE_NAME="$SANITIZED_FILENAME-${{ steps.file-info.outputs.architecture }}.dmg"
          FILE_PATH="${{ steps.file-info.outputs.path }}/${{ steps.file-info.outputs.name }}.dmg"
          RELEASE_ID="${{ needs.create-release.outputs.releaseId }}"
          curl -X POST -H "Authorization: Bearer $GH_TOKEN" \
            -H "Content-Type: application/octet-stream" \
            --data-binary "@$FILE_PATH" \
            "https://uploads.github.com/repos/$PUBLISH_REPO/releases/$RELEASE_ID/assets?name=$PUBLISH_FILE_NAME"

      - name: Upload artifact (MacOS)
        if: matrix.settings.platform == 'macos-latest'
        uses: actions/upload-artifact@v7
        with:
          name: ${{ steps.file-info.outputs.name }}-${{ steps.file-info.outputs.architecture }}.dmg
          path: ${{ steps.file-info.outputs.path }}/${{ steps.file-info.outputs.name }}.dmg

      # Windows release
      - name: Upload Windows artifact (Windows)
        if: matrix.settings.platform == 'windows-latest'
        uses: actions/upload-artifact@v7
        with:
          name: ${{ steps.file-info.outputs.filename }}
          path: ${{ steps.file-info.outputs.path }}/${{ steps.file-info.outputs.filename }}

      # Linux release
      - name: Upload Linux artifact (Linux)
        if: matrix.settings.platform == 'ubuntu-22.04'
        uses: actions/upload-artifact@v7
        with:
          name: ${{ steps.file-info.outputs.filename }}
          path: ${{ steps.file-info.outputs.path }}/${{ steps.file-info.outputs.filename }}

  publish-release:
    runs-on: ubuntu-latest
    needs: [get-version, check-version, create-release, package-tauri]
    if: needs.get-version.outputs.should-publish != '' && needs.check-version.outputs.should-skip != 'true'
    env:
      RELEASE_ID: ${{ needs.create-release.outputs.releaseId }}
    steps:
      - uses: actions/checkout@v6

      - name: Publish release
        run: |
          curl -X PATCH -H "Authorization: Bearer $GH_TOKEN" -d '{"draft": false}' "https://api.github.com/repos/$PUBLISH_REPO/releases/$RELEASE_ID"

      - name: Update Gist with JSON
        run: |
          ASSET_ID=$(curl -s -H "Authorization: Bearer $GH_TOKEN" "https://api.github.com/repos/$PUBLISH_REPO/releases/$RELEASE_ID/assets" | jq -r '.[] | select(.name == "latest.json") | .id')
          JSON_CONTENT=$(curl -sSL -H "Accept: application/octet-stream" -H "Authorization: token $GH_TOKEN" "https://api.github.com/repos/$PUBLISH_REPO/releases/assets/$ASSET_ID")
          GIST_CONTENT=$(jq -n --arg json "$JSON_CONTENT" '{"files":{"updater.json":{"content":$json}}}')
          curl -X PATCH -H "Authorization: token $GH_TOKEN" -d "$GIST_CONTENT" "https://api.github.com/gists/$UPDATER_GIST_ID"
