name: Release

on:
  push:
    tags:
      - "v*"
  workflow_dispatch:
    inputs:
      version:
        description: "Version tag (e.g., v1.0.0)"
        required: true
        default: "v1.0.0"

jobs:
  # Get version first (quick job)
  get-version:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
      is_prerelease: ${{ steps.version.outputs.is_prerelease }}
    steps:
      - name: Get version
        id: version
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            VERSION="${{ github.event.inputs.version }}"
          else
            VERSION="${GITHUB_REF#refs/tags/}"
          fi
          echo "version=$VERSION" >> $GITHUB_OUTPUT

          # Check if version contains -preview, -beta, -rc, or -alpha (NOT -hotfix)
          VERSION_LOWER=$(echo "$VERSION" | tr '[:upper:]' '[:lower:]')
          if [[ "$VERSION_LOWER" == *"-preview"* ]] || [[ "$VERSION_LOWER" == *"-beta"* ]] || [[ "$VERSION_LOWER" == *"-rc"* ]] || [[ "$VERSION_LOWER" == *"-alpha"* ]]; then
            echo "is_prerelease=true" >> $GITHUB_OUTPUT
            echo "Detected pre-release version: $VERSION"
          else
            echo "is_prerelease=false" >> $GITHUB_OUTPUT
            echo "Detected stable version: $VERSION"
          fi

  # Android and iOS build in PARALLEL
  build-android:
    runs-on: ubuntu-latest
    needs: get-version

    steps:
      - name: Free disk space
        run: |
          # Remove large unused tools (~15GB total)
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /opt/ghc
          sudo rm -rf /opt/hostedtoolcache/CodeQL
          sudo rm -rf /usr/local/share/boost
          sudo rm -rf /usr/share/swift
          sudo rm -rf /usr/local/.ghcup
          # Clean docker images
          sudo docker image prune --all --force
          # Show available space
          df -h

      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          distribution: "temurin"
          java-version: "17"

      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: "1.25"
          cache-dependency-path: go_backend/go.sum

      # Cache Gradle for faster builds
      - name: Cache Gradle
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: gradle-${{ runner.os }}-

      - name: Install Android SDK & NDK
        run: |
          # Use pre-installed Android SDK on GitHub runners
          echo "ANDROID_HOME=$ANDROID_HOME"
          echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT"

          # Accept licenses
          yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses || true

          # Install NDK r27d LTS (required for 16KB page size support on Android 15+)
          # Platform android-36 and build-tools 36.0.0 for targetSdk 36 (Android 16)
          $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;27.3.13750724" "platforms;android-36" "build-tools;36.0.0"

          # Set NDK path
          echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/27.3.13750724" >> $GITHUB_ENV

      - name: Install gomobile
        run: |
          go install golang.org/x/mobile/cmd/gomobile@latest
          gomobile init

      - name: Build Go backend for Android
        working-directory: go_backend
        run: |
          mkdir -p ../android/app/libs
          gomobile bind -target=android -androidapi 24 -o ../android/app/libs/gobackend.aar .
        env:
          CGO_ENABLED: 1

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: "stable"
          cache: true

      - name: Get Flutter dependencies
        run: flutter pub get

      - name: Generate app icons
        run: dart run flutter_launcher_icons

      - name: Build APK (Release - unsigned)
        run: |
          flutter build apk --release --split-per-abi || true
          # Verify APKs were created
          ls -la build/app/outputs/flutter-apk/
          if [ ! -f "build/app/outputs/flutter-apk/app-arm64-v8a-release.apk" ]; then
            echo "ERROR: APK not found!"
            exit 1
          fi

      - name: Sign APKs
        uses: r0adkll/sign-android-release@v1
        id: sign_arm64
        with:
          releaseDirectory: build/app/outputs/flutter-apk
          signingKeyBase64: ${{ secrets.KEYSTORE_BASE64 }}
          alias: ${{ secrets.KEY_ALIAS }}
          keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }}
          keyPassword: ${{ secrets.KEY_PASSWORD }}
        env:
          BUILD_TOOLS_VERSION: "36.0.0"

      - name: Rename APKs
        run: |
          VERSION=${{ needs.get-version.outputs.version }}
          cd build/app/outputs/flutter-apk
          # Signed files have -signed suffix
          mv app-arm64-v8a-release-signed.apk SpotiFLAC-${VERSION}-arm64.apk || mv app-arm64-v8a-release.apk SpotiFLAC-${VERSION}-arm64.apk || true
          mv app-armeabi-v7a-release-signed.apk SpotiFLAC-${VERSION}-arm32.apk || mv app-armeabi-v7a-release.apk SpotiFLAC-${VERSION}-arm32.apk || true
          mv app-release-signed.apk SpotiFLAC-${VERSION}-universal.apk || mv app-release.apk SpotiFLAC-${VERSION}-universal.apk || true
          ls -la

      - name: Upload APK artifact
        uses: actions/upload-artifact@v4
        with:
          name: android-apk
          path: build/app/outputs/flutter-apk/SpotiFLAC-*.apk

  build-ios:
    runs-on: macos-latest
    needs: get-version # Only depends on version, NOT android build!

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: "1.25"
          cache-dependency-path: go_backend/go.sum

      # Cache CocoaPods
      - name: Cache CocoaPods
        uses: actions/cache@v4
        with:
          path: ios/Pods
          key: pods-${{ runner.os }}-${{ hashFiles('ios/Podfile.lock') }}
          restore-keys: pods-${{ runner.os }}-

      - name: Install gomobile
        run: |
          go install golang.org/x/mobile/cmd/gomobile@latest
          gomobile init

      - name: Build Go backend for iOS
        working-directory: go_backend
        run: |
          mkdir -p ../ios/Frameworks
          gomobile bind -target=ios -tags ios -o ../ios/Frameworks/Gobackend.xcframework .
        env:
          CGO_ENABLED: 1

      - name: Verify XCFramework created
        run: |
          ls -la ios/Frameworks/
          ls -la ios/Frameworks/Gobackend.xcframework/ || (echo "ERROR: XCFramework not found!" && exit 1)

      - name: Add XCFramework to Xcode project
        run: |
          # Install xcodeproj gem for modifying Xcode project
          sudo gem install xcodeproj

          # Create Ruby script to add framework
          cat > add_framework.rb << 'EOF'
          require 'xcodeproj'

          project_path = 'ios/Runner.xcodeproj'
          project = Xcodeproj::Project.open(project_path)

          # Get the main target
          target = project.targets.find { |t| t.name == 'Runner' }

          # Get or create Frameworks group
          frameworks_group = project.main_group.find_subpath('Frameworks', true)
          frameworks_group ||= project.main_group.new_group('Frameworks')

          # Add XCFramework reference
          framework_path = 'Frameworks/Gobackend.xcframework'
          framework_ref = frameworks_group.new_file(framework_path, :project)

          # Add to frameworks build phase
          frameworks_build_phase = target.frameworks_build_phase
          frameworks_build_phase.add_file_reference(framework_ref)

          # Add to embed frameworks build phase
          embed_phase = target.build_phases.find { |p| p.is_a?(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase) && p.name == 'Embed Frameworks' }
          if embed_phase
            build_file = embed_phase.add_file_reference(framework_ref)
            build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy', 'RemoveHeadersOnCopy'] }
          end

          project.save
          puts "Successfully added Gobackend.xcframework to Xcode project"
          EOF

          ruby add_framework.rb

      - name: Setup Flutter
        uses: subosito/flutter-action@v2
        with:
          channel: "stable"
          cache: true

      - name: Get Flutter dependencies
        run: flutter pub get

      - name: Generate app icons
        run: dart run flutter_launcher_icons

      - name: Build iOS (unsigned)
        run: |
          # Build Flutter iOS without codesigning
          flutter build ios --release --no-codesign --config-only

          # Use xcodebuild with code signing disabled
          cd ios
          xcodebuild -workspace Runner.xcworkspace \
            -scheme Runner \
            -configuration Release \
            -sdk iphoneos \
            -destination 'generic/platform=iOS' \
            -archivePath build/Runner.xcarchive \
            archive \
            CODE_SIGNING_ALLOWED=NO \
            CODE_SIGNING_REQUIRED=NO \
            CODE_SIGN_IDENTITY="" \
            DEVELOPMENT_TEAM=""

      - name: Create IPA
        run: |
          VERSION=${{ needs.get-version.outputs.version }}
          mkdir -p build/ios/ipa
          cd ios/build/Runner.xcarchive/Products/Applications
          mkdir Payload
          cp -r Runner.app Payload/
          # Use absolute path to avoid relative path issues
          zip -r $GITHUB_WORKSPACE/build/ios/ipa/SpotiFLAC-${VERSION}-ios-unsigned.ipa Payload
          rm -rf Payload

      - name: Verify IPA created
        run: |
          ls -la build/ios/ipa/
          VERSION=${{ needs.get-version.outputs.version }}
          if [ ! -f "build/ios/ipa/SpotiFLAC-${VERSION}-ios-unsigned.ipa" ]; then
            echo "ERROR: IPA not created!"
            exit 1
          fi

      - name: Upload IPA artifact
        uses: actions/upload-artifact@v4
        with:
          name: ios-ipa
          path: build/ios/ipa/SpotiFLAC-*.ipa

  create-release:
    runs-on: ubuntu-latest
    needs: [get-version, build-android, build-ios]
    permissions:
      contents: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Extract changelog for version
        id: changelog
        run: |
          VERSION=${{ needs.get-version.outputs.version }}
          VERSION_NUM=${VERSION#v}  # Remove 'v' prefix

          echo "Looking for version: $VERSION_NUM"

          # Extract changelog section for this version using sed
          # Find the line with version, then print until next version header or end
          CHANGELOG=$(sed -n "/^## \[$VERSION_NUM\]/,/^## \[/{ /^## \[$VERSION_NUM\]/d; /^## \[/d; p; }" CHANGELOG.md)

          # If no changelog found, use default message
          if [ -z "$CHANGELOG" ]; then
            echo "No changelog found for version $VERSION_NUM"
            CHANGELOG="See CHANGELOG.md for details."
          else
            echo "Found changelog content"
            # Remove trailing --- separator if present (CHANGELOG uses --- between versions)
            CHANGELOG=$(echo "$CHANGELOG" | sed '/^---$/d')
          fi

          # Save to file for multiline support
          echo "$CHANGELOG" > /tmp/changelog.txt
          echo "Extracted changelog:"
          cat /tmp/changelog.txt

      - name: Download Android APK
        uses: actions/download-artifact@v4
        with:
          name: android-apk
          path: ./release

      - name: Download iOS IPA
        uses: actions/download-artifact@v4
        with:
          name: ios-ipa
          path: ./release

      - name: Prepare release body
        run: |
          VERSION=${{ needs.get-version.outputs.version }}
          cat > /tmp/release_body.txt << 'HEADER'
          ### What's New
          HEADER

          cat /tmp/changelog.txt >> /tmp/release_body.txt

          REPO_OWNER="${{ github.repository_owner }}"
          REPO_NAME="${{ github.event.repository.name }}"
          
          cat >> /tmp/release_body.txt << FOOTER

          ---

          ### Downloads

          #### Android
          - **arm64**: \`SpotiFLAC-${VERSION}-arm64.apk\` (recommended for modern devices)
          - **arm32**: \`SpotiFLAC-${VERSION}-arm32.apk\` (older devices)

          #### iOS
          - **iOS**: \`SpotiFLAC-${VERSION}-ios-unsigned.ipa\` (sideload required)

          ### Installation
          **Android**: Enable "Install from unknown sources" and install the APK
          **iOS**: Use AltStore, Sideloadly, or similar tools to sideload the IPA

          ![arm64](https://img.shields.io/github/downloads/${REPO_OWNER}/${REPO_NAME}/${VERSION}/SpotiFLAC-${VERSION}-arm64.apk?style=flat-square&logo=android&label=arm64&color=3DDC84) ![arm32](https://img.shields.io/github/downloads/${REPO_OWNER}/${REPO_NAME}/${VERSION}/SpotiFLAC-${VERSION}-arm32.apk?style=flat-square&logo=android&label=arm32&color=3DDC84) ![iOS](https://img.shields.io/github/downloads/${REPO_OWNER}/${REPO_NAME}/${VERSION}/SpotiFLAC-${VERSION}-ios-unsigned.ipa?style=flat-square&logo=apple&label=iOS&color=0078D6)
          FOOTER

          echo "Release body:"
          cat /tmp/release_body.txt

      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ needs.get-version.outputs.version }}
          name: SpotiFLAC ${{ needs.get-version.outputs.version }}
          body_path: /tmp/release_body.txt
          files: ./release/*
          draft: false
          prerelease: ${{ needs.get-version.outputs.is_prerelease == 'true' }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  notify-telegram:
    runs-on: ubuntu-latest
    needs: [get-version, create-release]
    if: ${{ needs.get-version.outputs.is_prerelease != 'true' }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Download Android APK
        uses: actions/download-artifact@v4
        with:
          name: android-apk
          path: ./release

      - name: Download iOS IPA
        uses: actions/download-artifact@v4
        with:
          name: ios-ipa
          path: ./release

      - name: Extract changelog for version
        id: changelog
        run: |
          VERSION=${{ needs.get-version.outputs.version }}
          VERSION_NUM=${VERSION#v}

          # Extract changelog, limit to ~2500 chars for Telegram (4096 limit minus message overhead)
          # Use tr -d '\r' to handle CRLF line endings from Windows
          FULL_CHANGELOG=$(cat CHANGELOG.md | tr -d '\r' | sed -n "/^## \[$VERSION_NUM\]/,/^## \[/{ /^## \[$VERSION_NUM\]/d; /^## \[/d; p; }" | sed '/^---$/d')
          
          echo "DEBUG: Extracted changelog length: ${#FULL_CHANGELOG}"
          echo "DEBUG: First 200 chars: ${FULL_CHANGELOG:0:200}"
          
          if [ -z "$FULL_CHANGELOG" ]; then
            CHANGELOG="See release notes on GitHub for details."
          else
            # Convert GitHub Markdown to Telegram HTML:
            # - **text** → <b>text</b>
            # - `code` → <code>code</code>
            # - ### Header → <b>Header</b>
            # - Escape HTML special chars first
            # - Remove > blockquote prefix
            CHANGELOG=$(echo "$FULL_CHANGELOG" | \
              sed 's/^> //' | \
              sed 's/&/\&amp;/g' | \
              sed 's/</\&lt;/g' | \
              sed 's/>/\&gt;/g' | \
              sed 's/`\([^`]*\)`/<code>\1<\/code>/g' | \
              sed 's/\*\*\([^*]*\)\*\*/<b>\1<\/b>/g' | \
              sed 's/^### \(.*\)$/<b>\1<\/b>/g' | \
              sed 's/^## \(.*\)$/<b>\1<\/b>/g' | \
              sed 's/^- /• /g' | \
              sed 's/^  - /  ◦ /g')
            
            # Take first 2500 characters, then cut at last complete line
            CHANGELOG=$(echo "$CHANGELOG" | head -c 2500 | sed '$d')
            
            # Check if truncated
            FULL_LEN=${#FULL_CHANGELOG}
            if [ $FULL_LEN -gt 2500 ]; then
              CHANGELOG="${CHANGELOG}"$'\n\n... (see full changelog on GitHub)'
            fi
          fi

          echo "$CHANGELOG" > /tmp/changelog.txt
          echo "DEBUG: Final changelog:"
          cat /tmp/changelog.txt

      - name: Send to Telegram Channel
        env:
          TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
          TELEGRAM_CHANNEL_ID: ${{ secrets.TELEGRAM_CHANNEL_ID }}
        run: |
          VERSION=${{ needs.get-version.outputs.version }}
          CHANGELOG=$(cat /tmp/changelog.txt)
          
          # Find APK files
          ARM64_APK=$(find ./release -name "*arm64*.apk" | head -1)
          ARM32_APK=$(find ./release -name "*arm32*.apk" | head -1)
          
          # Prepare message with changelog (HTML format)
          printf '%s\n' \
            "<b>SpotiFLAC Mobile ${VERSION} Released!</b>" \
            "" \
            "<b>What's New:</b>" \
            "${CHANGELOG}" \
            "" \
            "<a href=\"https://github.com/${{ github.repository }}/releases/tag/${VERSION}\">View Release Notes</a>" \
            > /tmp/telegram_message.txt

          MESSAGE=$(cat /tmp/telegram_message.txt)

          # Send message first (using HTML parse mode)
          # Use --data-urlencode for proper encoding of special chars (+, &, etc.)
          # Use || true to ensure file uploads continue even if message fails
          curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
            --data-urlencode "chat_id=${TELEGRAM_CHANNEL_ID}" \
            --data-urlencode "text=${MESSAGE}" \
            --data-urlencode "parse_mode=HTML" \
            --data-urlencode "disable_web_page_preview=true" || true

          # Upload arm64 APK to channel
          if [ -f "$ARM64_APK" ]; then
            echo "Uploading arm64 APK to Telegram..."
            curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" \
              -F chat_id="${TELEGRAM_CHANNEL_ID}" \
              -F document=@"${ARM64_APK}" \
              -F caption="SpotiFLAC ${VERSION} - arm64 (recommended)"
          fi

          # Upload arm32 APK to channel
          if [ -f "$ARM32_APK" ]; then
            echo "Uploading arm32 APK to Telegram..."
            curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" \
              -F chat_id="${TELEGRAM_CHANNEL_ID}" \
              -F document=@"${ARM32_APK}" \
              -F caption="SpotiFLAC ${VERSION} - arm32"
          fi

          # Upload iOS IPA to channel
          IOS_IPA=$(find ./release -name "*ios*.ipa" | head -1)
          if [ -f "$IOS_IPA" ]; then
            echo "Uploading iOS IPA to Telegram..."
            curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" \
              -F chat_id="${TELEGRAM_CHANNEL_ID}" \
              -F document=@"${IOS_IPA}" \
              -F caption="SpotiFLAC ${VERSION} - iOS (unsigned, sideload required)"
          fi

          echo "Telegram notification sent!"
