# .github/workflows/release.yml

name: Release

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'
      - 'v[0-9]+.[0-9]+.[0-9]+-*' # e.g., v1.2.3-beta, v1.2.3-rc1
  workflow_dispatch:
    inputs:
      tag:
        description: 'Release tag (e.g., v0.3.0)'
        required: true
        type: string

concurrency:
  group: release-${{ github.ref_name || github.event.inputs.tag }}
  cancel-in-progress: true

permissions:
  contents: write

env:
  BUILD_TYPE: Release

jobs:
  # ======================================================================================
  #  VALIDATE & PREPARE RELEASE
  # ======================================================================================
  prepare-release:
    name: "✅ Validate & Prepare"
    runs-on: ubuntu-latest
    outputs:
      tag_name: ${{ steps.validate.outputs.tag_name }}
      release_notes: ${{ steps.notes.outputs.content }}
      is_prerelease: ${{ steps.validate.outputs.is_prerelease }}

    steps:
      - name: "Checkout Code"
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Required for changelog extraction

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version: '3.x'

      - name: "Determine & Validate Tag"
        id: validate
        shell: bash
        run: |
          set -euo pipefail
          
          if [[ "${{ github.event_name }}" == "push" ]]; then
            TAG="${{ github.ref_name }}"
          else
            TAG="${{ github.event.inputs.tag }}"
          fi

          echo "Validating tag: ${TAG}"
          if [[ ! "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$ ]]; then
            echo "::error::Tag '${TAG}' must follow semantic versioning (e.g., v1.2.3 or v1.2.3-beta)."
            exit 1
          fi

          # Determine if it's a pre-release
          if [[ "${TAG}" =~ - ]]; then
            echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
          else
            echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
          fi

          echo "tag_name=${TAG}" >> "$GITHUB_OUTPUT"
          echo "VALIDATED_TAG=${TAG}" >> "$GITHUB_ENV"
          echo "✅ Tag is valid and processed."

      - name: "Generate Release Notes"
        shell: bash
        run: |
          set -euo pipefail
          VERSION="${VALIDATED_TAG#v}"
          
          if [[ -f scripts/extract_changelog.py ]]; then
            echo "Attempting to extract changelog for version ${VERSION}..."
            python3 scripts/extract_changelog.py "${VERSION}" > release_notes.md
          else
            echo "::warning::'scripts/extract_changelog.py' not found. Creating default release notes."
            echo "# Yaze ${{ env.VALIDATED_TAG }} Release Notes" > release_notes.md
            echo "" >> release_notes.md
            echo "For a detailed list of changes, please see the project's commit history or changelog file." >> release_notes.md
          fi
          
          echo "Generated release notes:"
          cat release_notes.md

      - name: "Store Release Notes"
        id: notes
        shell: bash
        run: |
          {
            echo 'content<<EOF'
            cat release_notes.md
            echo 'EOF'
          } >> "$GITHUB_OUTPUT"

  # ======================================================================================
  #  BUILD & PACKAGE
  # ======================================================================================
  build-and-package:
    name: "📦 Build (${{ matrix.name }})"
    needs: prepare-release
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: "Windows x64"
            os: windows-2022
            artifact_name: "yaze-windows-x64"
          - name: "macOS arm64"
            os: macos-14
            mac_arch: arm64
            artifact_name: "yaze-macos-arm64-slice"
          - name: "macOS x86_64"
            os: macos-14
            mac_arch: x86_64
            artifact_name: "yaze-macos-x86_64-slice"
          - name: "Linux x64"
            os: ubuntu-22.04
            artifact_name: "yaze-linux-x64"

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

    steps:
      - name: "Checkout Code"
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: "Set up vcpkg (Windows only)"
        if: runner.os == 'Windows'
        uses: lukka/run-vcpkg@v11
        id: vcpkg
        continue-on-error: true
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          vcpkgGitCommitId: '01f602195983451bc83e72f4214af2cbc495aa94'  # 2024.10.21 release
          runVcpkgInstall: true
      
      - name: "Retry vcpkg setup (Windows only)"
        if: runner.os == 'Windows' && steps.vcpkg.outcome == 'failure'
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: '${{ github.workspace }}/vcpkg'
          vcpkgGitCommitId: '01f602195983451bc83e72f4214af2cbc495aa94'
          runVcpkgInstall: true
          doNotUpdateVcpkg: true  # Use existing clone on retry

      - name: "Install Dependencies"
        id: deps
        shell: bash
        continue-on-error: true
        run: |
          if [[ "${{ runner.os }}" == "Linux" ]]; then
            sudo apt-get update
            sudo apt-get install -y \
              build-essential ninja-build pkg-config \
              libglew-dev libxext-dev libwavpack-dev libboost-all-dev \
              libpng-dev python3-dev libpython3-dev \
              libasound2-dev libpulse-dev libx11-dev libxrandr-dev libxcursor-dev \
              libxinerama-dev libxi-dev
            # Note: libabsl-dev removed - gRPC uses bundled Abseil via FetchContent when enabled
          elif [[ "${{ runner.os }}" == "macOS" ]]; then
            brew install ninja cmake pkg-config
          fi
      
      - name: "Retry Dependencies (if failed)"
        if: steps.deps.outcome == 'failure'
        shell: bash
        run: |
          echo "::warning::First dependency install failed, retrying..."
          if [[ "${{ runner.os }}" == "Linux" ]]; then
            sudo apt-get clean
            sudo apt-get update --fix-missing
            sudo apt-get install -y \
              build-essential ninja-build pkg-config \
              libglew-dev libxext-dev libwavpack-dev libboost-all-dev \
              libpng-dev python3-dev libpython3-dev \
              libasound2-dev libpulse-dev libx11-dev libxrandr-dev libxcursor-dev \
              libxinerama-dev libxi-dev
          elif [[ "${{ runner.os }}" == "macOS" ]]; then
            brew update
            brew install ninja cmake pkg-config
          fi

      - name: "Configure (Windows)"
        if: runner.os == 'Windows'
        id: configure_windows
        shell: pwsh
        run: |
          Write-Host "::group::CMake Configuration (Windows)" -ForegroundColor Cyan
          
          $vcpkgToolchain = "${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake" -replace '\\', '/'
          Write-Host "Using vcpkg toolchain: $vcpkgToolchain"
          
          cmake -B build -G "Visual Studio 17 2022" -A x64 `
            -DCMAKE_BUILD_TYPE=$env:BUILD_TYPE `
            -DCMAKE_TOOLCHAIN_FILE="$vcpkgToolchain" `
            -DVCPKG_TARGET_TRIPLET=x64-windows-static `
            -DVCPKG_MANIFEST_MODE=ON `
            -DCMAKE_CXX_FLAGS="/Dgoogle_protobuf_undef_DWORD=1" `
            -DYAZE_BUILD_TESTS=OFF 2>&1 | Tee-Object -FilePath cmake_config.log
          
          if ($LASTEXITCODE -ne 0) {
            Write-Host "::error::CMake configuration failed with exit code $LASTEXITCODE"
            exit $LASTEXITCODE
          }
          
          Write-Host "::endgroup::"
      
      - name: "Configure (macOS)"
        if: runner.os == 'macOS'
        id: configure_macos
        shell: bash
        run: |
          set -e
          echo "::group::CMake Configuration (macOS)"
          cmake -B build -G Ninja \
            -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
            -DCMAKE_OSX_ARCHITECTURES=${{ matrix.mac_arch }} \
            -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \
            -DYAZE_BUILD_TESTS=OFF 2>&1 | tee cmake_config.log
          echo "::endgroup::"
      
      - name: "Configure (Linux)"
        if: runner.os == 'Linux'
        id: configure_linux
        shell: bash
        run: |
          set -e
          echo "::group::CMake Configuration (Linux)"
          cmake -B build -G Ninja \
            -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
            -DYAZE_BUILD_TESTS=OFF 2>&1 | tee cmake_config.log
          echo "::endgroup::"
      
      - name: "Report Configure Failure"
        if: |
          failure() && 
          (steps.configure_windows.outcome == 'failure' || 
           steps.configure_macos.outcome == 'failure' || 
           steps.configure_linux.outcome == 'failure')
        shell: bash
        run: |
          echo "::error::CMake configuration failed for ${{ matrix.name }}"
          if [ -f cmake_config.log ]; then
            echo "::group::CMake Configuration Log (last 50 lines)"
            tail -50 cmake_config.log
            echo "::endgroup::"
          fi
          if [ -f build/CMakeFiles/CMakeError.log ]; then
            echo "::group::CMake Error Log"
            cat build/CMakeFiles/CMakeError.log
            echo "::endgroup::"
          fi

      - name: "Build"
        id: build
        run: cmake --build build --config ${{ env.BUILD_TYPE }} --parallel 2>&1 | tee build.log
      
      - name: "Report Build Failure"
        if: failure() && steps.build.outcome == 'failure'
        shell: bash
        run: |
          echo "::error::Build failed for ${{ matrix.name }}"
          if [ -f build.log ]; then
            echo "::group::Build Log (last 100 lines)"
            tail -100 build.log
            echo "::endgroup::"
            
            echo "::group::Build Errors"
            grep -i "error" build.log | head -20 || true
            echo "::endgroup::"
          fi
      
      - name: "Upload Build Logs on Failure"
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: release-build-logs-${{ matrix.artifact_name }}
          path: |
            cmake_config.log
            build.log
            build/CMakeFiles/CMakeError.log
            build/CMakeFiles/CMakeOutput.log
          if-no-files-found: ignore
          retention-days: 7

      - name: "Package Artifacts"
        shell: bash
        run: |
          set -euo pipefail
          ARTIFACT_NAME="${{ matrix.artifact_name }}"
          
          # Create staging directory
          mkdir -p stage
          
          if [[ "${{ runner.os }}" == "Windows" ]]; then
            # Windows uses Visual Studio generator: build/bin/Release/
            echo "Packaging Windows artifacts..."
            if [[ ! -f build/bin/${{ env.BUILD_TYPE }}/yaze.exe ]]; then
              echo "::error::Windows binary not found at build/bin/${{ env.BUILD_TYPE }}/yaze.exe"
              ls -la build/bin/ || true
              exit 1
            fi
            cp -r build/bin/${{ env.BUILD_TYPE }}/* stage/
            cp -r assets/ stage/assets/
            cp LICENSE README.md stage/
            (cd stage && powershell -Command "Compress-Archive -Path * -DestinationPath ../${ARTIFACT_NAME}.zip")
            echo "Created ${ARTIFACT_NAME}.zip"
            
          elif [[ "${{ runner.os }}" == "macOS" ]]; then
            # macOS creates app bundle: build/bin/yaze.app
            echo "Packaging macOS artifacts..."
            if [[ ! -d build/bin/yaze.app ]]; then
              echo "::error::macOS app bundle not found at build/bin/yaze.app"
              ls -la build/bin/ || true
              exit 1
            fi
            cp -R build/bin/yaze.app stage/yaze.app
            echo "Staged yaze.app slice for ${ARTIFACT_NAME}"
            
          else # Linux
            # Linux uses Ninja generator: build/bin/yaze (no subdirectory)
            echo "Packaging Linux artifacts..."
            if [[ -f build/bin/yaze ]]; then
              echo "Found binary at build/bin/yaze"
              cp build/bin/yaze stage/
            else
              echo "::error::Linux binary not found at build/bin/yaze"
              ls -la build/bin/ || true
              exit 1
            fi
            
            # Copy assets from source tree
            if [[ -d assets ]]; then
              cp -r assets/ stage/assets/
            else
              echo "::error::Assets directory not found"
              exit 1
            fi
            
            cp LICENSE README.md stage/
            tar -czf "${ARTIFACT_NAME}.tar.gz" -C stage .
            echo "Created ${ARTIFACT_NAME}.tar.gz"
          fi

      - name: "Upload Artifact (Windows)"
        if: runner.os == 'Windows'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact_name }}
          path: ${{ matrix.artifact_name }}.zip
          if-no-files-found: error
          retention-days: 5

      - name: "Upload Artifact (macOS)"
        if: runner.os == 'macOS'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact_name }}
          path: stage/yaze.app
          if-no-files-found: error
          retention-days: 5

      - name: "Upload Artifact (Linux)"
        if: runner.os == 'Linux'
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.artifact_name }}
          path: ${{ matrix.artifact_name }}.tar.gz
          if-no-files-found: error
          retention-days: 5
      
      - name: "Generate Build Summary"
        if: always()
        shell: bash
        run: |
          echo "## Release Build Summary - ${{ matrix.name }}" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          
          echo "### Configuration" >> $GITHUB_STEP_SUMMARY
          echo "- **Platform**: ${{ matrix.os }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Artifact**: ${{ matrix.artifact_name }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Build Type**: ${{ env.BUILD_TYPE }}" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          
          echo "### Build Status" >> $GITHUB_STEP_SUMMARY
          CONFIGURE_OUTCOME="${{ steps.configure_windows.outcome || steps.configure_macos.outcome || steps.configure_linux.outcome }}"
          if [[ "$CONFIGURE_OUTCOME" == "success" ]]; then
            echo "- ✅ Configure: Success" >> $GITHUB_STEP_SUMMARY
          else
            echo "- ❌ Configure: Failed" >> $GITHUB_STEP_SUMMARY
          fi
          
          if [[ "${{ steps.build.outcome }}" == "success" ]]; then
            echo "- ✅ Build: Success" >> $GITHUB_STEP_SUMMARY
          else
            echo "- ❌ Build: Failed" >> $GITHUB_STEP_SUMMARY
          fi
          
          # Show package size if build succeeded
          if [[ "${{ steps.build.outcome }}" == "success" ]]; then
            if [[ "${{ runner.os }}" == "Windows" && -f "${{ matrix.artifact_name }}.zip" ]]; then
              SIZE=$(du -h "${{ matrix.artifact_name }}.zip" | cut -f1)
              echo "- 📦 Artifact Size: $SIZE" >> $GITHUB_STEP_SUMMARY
            elif [[ "${{ runner.os }}" == "Linux" && -f "${{ matrix.artifact_name }}.tar.gz" ]]; then
              SIZE=$(du -h "${{ matrix.artifact_name }}.tar.gz" | cut -f1)
              echo "- 📦 Artifact Size: $SIZE" >> $GITHUB_STEP_SUMMARY
            elif [[ "${{ runner.os }}" == "macOS" && -d "stage/yaze.app" ]]; then
              SIZE=$(du -sh "stage/yaze.app" | cut -f1)
              echo "- 📦 Artifact Size: $SIZE" >> $GITHUB_STEP_SUMMARY
            fi
          fi

  # ======================================================================================
  #  MERGE MACOS & CREATE UNIVERSAL BINARY
  # ======================================================================================
  merge-macos-universal:
    name: "🍎 Merge macOS Universal"
    needs: build-and-package
    runs-on: macos-14
    steps:
      - name: "Download arm64 Slice"
        uses: actions/download-artifact@v4
        with:
          name: yaze-macos-arm64-slice
          path: arm64-slice

      - name: "Download x86_64 Slice"
        uses: actions/download-artifact@v4
        with:
          name: yaze-macos-x86_64-slice
          path: x86_64-slice

      - name: "Create Universal Binary"
        shell: bash
        run: |
          set -euo pipefail
          
          # The artifacts are downloaded as yaze.app directly
          ARM_APP="arm64-slice/yaze.app"
          X64_APP="x86_64-slice/yaze.app"
          
          echo "Checking downloaded artifacts..."
          ls -la arm64-slice/
          ls -la x86_64-slice/
          
          # Use the arm64 bundle as the base
          cp -R "${ARM_APP}" ./yaze.app
          
          echo "Merging executables..."
          lipo -create "${ARM_APP}/Contents/MacOS/yaze" "${X64_APP}/Contents/MacOS/yaze" -output "./yaze.app/Contents/MacOS/yaze"
          
          echo "Verifying universal binary..."
          lipo -info "./yaze.app/Contents/MacOS/yaze"
          
          echo "Creating DMG..."
          hdiutil create -fs HFS+ -srcfolder ./yaze.app -volname "yaze ${{ needs.prepare-release.outputs.tag_name }}" yaze-macos-universal.dmg

      - name: "Upload Universal macOS Artifact"
        uses: actions/upload-artifact@v4
        with:
          name: yaze-macos-universal
          path: yaze-macos-universal.dmg
          if-no-files-found: error
          retention-days: 5

  # ======================================================================================
  #  CREATE GITHUB RELEASE
  # ======================================================================================
  create-github-release:
    name: "🚀 Create GitHub Release"
    needs: [prepare-release, build-and-package, merge-macos-universal]
    runs-on: ubuntu-latest
    steps:
      - name: "Download Windows Artifact"
        uses: actions/download-artifact@v4
        with:
          name: yaze-windows-x64
          path: release-artifacts

      - name: "Download Linux Artifact"
        uses: actions/download-artifact@v4
        with:
          name: yaze-linux-x64
          path: release-artifacts

      - name: "Download macOS Universal Artifact"
        uses: actions/download-artifact@v4
        with:
          name: yaze-macos-universal
          path: release-artifacts

      - name: "List Release Artifacts"
        run: ls -lR release-artifacts

      - name: "Create/Update Release"
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.prepare-release.outputs.tag_name }}
          name: "yaze ${{ needs.prepare-release.outputs.tag_name }}"
          body: ${{ needs.prepare-release.outputs.release_notes }}
          draft: false
          prerelease: ${{ needs.prepare-release.outputs.is_prerelease }}
          files: release-artifacts/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
