name: Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: 'Release version (e.g., 0.6.0)'
        required: true
        type: string

env:
  CARGO_TERM_COLOR: always

jobs:
  # Update version in Cargo.toml
  prepare-release:
    name: Prepare Release
    runs-on: ubuntu-latest
    permissions:
      contents: write
    outputs:
      version: ${{ steps.set-version.outputs.version }}
      version_tag: ${{ steps.set-version.outputs.version_tag }}
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Set version outputs
        id: set-version
        run: |
          VERSION="${{ github.event.inputs.version }}"
          echo "version=${VERSION}" >> $GITHUB_OUTPUT
          echo "version_tag=v${VERSION}" >> $GITHUB_OUTPUT

      - name: Update Cargo.toml version
        run: |
          VERSION="${{ github.event.inputs.version }}"
          sed -i "s/^version = .*/version = \"${VERSION}\"/" Cargo.toml

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Update Cargo.lock
        run: cargo update -p cooklang-find

      - name: Commit version bump
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add Cargo.toml Cargo.lock
          git diff --cached --quiet && echo "Version already up to date" || (git commit -m "chore: bump version to ${{ github.event.inputs.version }}" && git push origin main)

  # Build iOS artifacts
  build-ios:
    name: Build iOS
    needs: prepare-release
    runs-on: macos-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          ref: main

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-apple-ios,aarch64-apple-ios-sim,x86_64-apple-ios

      - name: Cache Rust dependencies
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-ios-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-ios-cargo-

      - name: Build XCFramework
        run: ./scripts/build-swift.sh --all

      - name: Package iOS artifacts
        run: |
          cd bindings/swift
          mv CooklangFind.xcframework CooklangFindFFI.xcframework
          zip -r ../../CooklangFindFFI.xcframework.zip CooklangFindFFI.xcframework
          mkdir -p CooklangFind/Sources/CooklangFind
          cp Sources/CooklangFind/CooklangFind.swift CooklangFind/Sources/CooklangFind/
          zip -r ../../CooklangFind-ios.zip CooklangFind CooklangFindFFI.xcframework Sources/CooklangFind

      - name: Upload iOS artifacts
        uses: actions/upload-artifact@v4
        with:
          name: ios-artifacts
          path: |
            CooklangFindFFI.xcframework.zip
            CooklangFind-ios.zip
            bindings/swift/Sources/CooklangFind/CooklangFind.swift

  # Build Android artifacts
  build-android:
    name: Build Android
    needs: prepare-release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          ref: main

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-linux-android,armv7-linux-androideabi,x86_64-linux-android

      - name: Cache Rust dependencies
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-android-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-android-cargo-

      - name: Setup Android NDK
        uses: android-actions/setup-android@v3

      - name: Install NDK
        run: |
          sdkmanager --install "ndk;26.1.10909125"
          echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/26.1.10909125" >> $GITHUB_ENV

      - name: Install cargo-ndk
        run: command -v cargo-ndk || cargo install cargo-ndk --locked

      - name: Build uniffi-bindgen for host
        run: cargo build --features cli --bin uniffi-bindgen --release

      - name: Build Android targets
        run: |
          cargo ndk --target aarch64-linux-android --platform 21 build --release
          cargo ndk --target armv7-linux-androideabi --platform 21 build --release
          cargo ndk --target x86_64-linux-android --platform 21 build --release

      - name: Generate Kotlin bindings
        run: |
          rm -rf target/android/kotlin
          mkdir -p target/android/kotlin
          ./target/release/uniffi-bindgen generate \
            --library target/aarch64-linux-android/release/libcooklang_find.so \
            --language kotlin \
            --config uniffi.toml \
            --out-dir target/android/kotlin
          echo "Generated Kotlin files:"
          find target/android/kotlin -name "*.kt" -type f

      - name: Organize JNI libraries
        run: |
          mkdir -p target/android/jniLibs/{arm64-v8a,armeabi-v7a,x86_64}
          cp target/aarch64-linux-android/release/libcooklang_find.so target/android/jniLibs/arm64-v8a/
          cp target/armv7-linux-androideabi/release/libcooklang_find.so target/android/jniLibs/armeabi-v7a/
          cp target/x86_64-linux-android/release/libcooklang_find.so target/android/jniLibs/x86_64/

      - name: Create Android library module
        run: |
          mkdir -p target/android/cooklang-find-android/src/main/kotlin
          mkdir -p target/android/cooklang-find-android/src/main/jniLibs

          cp -R target/android/jniLibs/* target/android/cooklang-find-android/src/main/jniLibs/

          find target/android/kotlin -name "*.kt" -exec cp {} target/android/cooklang-find-android/src/main/kotlin/ \;

          cat > target/android/cooklang-find-android/build.gradle.kts << 'EOF'
          plugins {
              id("com.android.library")
              id("org.jetbrains.kotlin.android")
          }

          android {
              namespace = "org.cooklang.find"
              compileSdk = 34

              defaultConfig {
                  minSdk = 21
                  testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                  consumerProguardFiles("consumer-rules.pro")
              }

              buildTypes {
                  release {
                      isMinifyEnabled = false
                      proguardFiles(
                          getDefaultProguardFile("proguard-android-optimize.txt"),
                          "proguard-rules.pro"
                      )
                  }
              }
              compileOptions {
                  sourceCompatibility = JavaVersion.VERSION_1_8
                  targetCompatibility = JavaVersion.VERSION_1_8
              }
              kotlinOptions {
                  jvmTarget = "1.8"
              }
              sourceSets {
                  getByName("main") {
                      jniLibs.srcDirs("src/main/jniLibs")
                  }
              }
          }

          dependencies {
              implementation("net.java.dev.jna:jna:5.14.0@aar")
              implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
              implementation("androidx.annotation:annotation:1.7.0")
          }
          EOF

          mkdir -p target/android/cooklang-find-android/src/main
          cat > target/android/cooklang-find-android/src/main/AndroidManifest.xml << 'EOF'
          <?xml version="1.0" encoding="utf-8"?>
          <manifest xmlns:android="http://schemas.android.com/apk/res/android">
          </manifest>
          EOF

          cat > target/android/cooklang-find-android/proguard-rules.pro << 'EOF'
          -keep class org.cooklang.** { *; }
          -keep class com.sun.jna.** { *; }
          -keepclassmembers class * extends com.sun.jna.** { public *; }
          EOF

          cat > target/android/cooklang-find-android/consumer-rules.pro << 'EOF'
          -keep class org.cooklang.** { *; }
          EOF

      - name: Package Android artifacts
        run: |
          cd target/android
          zip -r ../../cooklang-find-android.zip cooklang-find-android jniLibs kotlin

      - name: Upload Android artifacts
        uses: actions/upload-artifact@v4
        with:
          name: android-artifacts
          path: cooklang-find-android.zip

  # Update Package.swift with correct checksum (BEFORE creating tag)
  update-package-swift:
    name: Update Package.swift
    needs: [prepare-release, build-ios]
    runs-on: macos-latest
    permissions:
      contents: write
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          ref: main
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Download iOS artifacts
        uses: actions/download-artifact@v4
        with:
          name: ios-artifacts

      - name: Compute checksum
        id: checksum
        run: |
          CHECKSUM=$(swift package compute-checksum CooklangFindFFI.xcframework.zip)
          echo "checksum=${CHECKSUM}" >> $GITHUB_OUTPUT
          echo "Computed checksum: ${CHECKSUM}"

      - name: Update Package.swift
        run: |
          VERSION="${{ needs.prepare-release.outputs.version_tag }}"
          CHECKSUM="${{ steps.checksum.outputs.checksum }}"

          cat > Package.swift << EOF
          // swift-tools-version:5.5
          // The swift-tools-version declares the minimum version of Swift required to build this package.

          import PackageDescription

          let package = Package(
              name: "CooklangFind",
              platforms: [
                  .iOS(.v13),
                  .macOS(.v10_15)
              ],
              products: [
                  .library(
                      name: "CooklangFind",
                      targets: ["CooklangFind", "CooklangFindFFI"]
                  ),
              ],
              targets: [
                  .target(
                      name: "CooklangFind",
                      dependencies: ["CooklangFindFFI"],
                      path: "Sources/CooklangFind"
                  ),
                  .binaryTarget(
                      name: "CooklangFindFFI",
                      url: "https://github.com/cooklang/cooklang-find/releases/download/${VERSION}/CooklangFindFFI.xcframework.zip",
                      checksum: "${CHECKSUM}"
                  ),
              ]
          )
          EOF

      - name: Copy generated Swift bindings
        run: |
          mkdir -p Sources/CooklangFind
          cp bindings/swift/Sources/CooklangFind/CooklangFind.swift Sources/CooklangFind/

      - name: Commit Package.swift and Sources
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add Package.swift Sources/
          git commit -m "Release ${{ needs.prepare-release.outputs.version_tag }}"
          git push origin main

  # Create tags and release (AFTER Package.swift is updated)
  create-release:
    name: Create Tags and Release
    needs: [prepare-release, build-ios, build-android, update-package-swift]
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          ref: main
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Download iOS artifacts
        uses: actions/download-artifact@v4
        with:
          name: ios-artifacts

      - name: Download Android artifacts
        uses: actions/download-artifact@v4
        with:
          name: android-artifacts

      - name: Create and push tag
        run: |
          VERSION_TAG="${{ needs.prepare-release.outputs.version_tag }}"

          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"

          git pull origin main
          git tag "${VERSION_TAG}"
          git push origin "${VERSION_TAG}"

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ needs.prepare-release.outputs.version_tag }}
          name: Release ${{ needs.prepare-release.outputs.version_tag }}
          draft: false
          prerelease: false
          generate_release_notes: true
          files: |
            CooklangFindFFI.xcframework.zip
            CooklangFind-ios.zip
            cooklang-find-android.zip
          body: |
            ## Mobile SDK Release ${{ needs.prepare-release.outputs.version_tag }}

            ### iOS (Swift Package Manager)

            Add to your `Package.swift` or Xcode project:
            ```swift
            .package(url: "https://github.com/cooklang/cooklang-find.git", from: "${{ needs.prepare-release.outputs.version }}")
            ```

            **Downloads:**
            - `CooklangFindFFI.xcframework.zip` - XCFramework binary (used by Package.swift)
            - `CooklangFind-ios.zip` - Full package with Swift sources for manual integration

            ### Android (GitHub Packages Maven)

            Add to your `settings.gradle.kts`:
            ```kotlin
            dependencyResolutionManagement {
                repositories {
                    maven {
                        url = uri("https://maven.pkg.github.com/cooklang/cooklang-find")
                        credentials {
                            username = System.getenv("GITHUB_ACTOR")
                            password = System.getenv("GITHUB_TOKEN")
                        }
                    }
                }
            }
            ```

            Add to your `build.gradle.kts`:
            ```kotlin
            implementation("org.cooklang:cooklang-find:${{ needs.prepare-release.outputs.version }}")
            ```

            Or download `cooklang-find-android.zip` which contains:
            - `cooklang-find-android/` - Android library module
            - `jniLibs/` - Native libraries for all architectures
            - `kotlin/` - Kotlin bindings source files

            ### Supported Architectures

            **iOS:**
            - arm64 (devices)
            - arm64 (simulator, Apple Silicon)
            - x86_64 (simulator, Intel)

            **Android:**
            - arm64-v8a
            - armeabi-v7a
            - x86_64

            See the README for integration instructions.

  # Publish Android package to GitHub Packages
  publish-android:
    name: Publish Android to GitHub Packages
    needs: [prepare-release, build-android, create-release]
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
        with:
          ref: main

      - name: Download Android artifacts
        uses: actions/download-artifact@v4
        with:
          name: android-artifacts

      - name: Extract Android artifacts
        run: |
          mkdir -p target/android
          unzip cooklang-find-android.zip -d target/android/

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

      - name: Setup Android SDK
        uses: android-actions/setup-android@v3

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v3

      - name: Configure Android library for publishing
        run: |
          VERSION="${{ needs.prepare-release.outputs.version }}"
          ANDROID_DIR="target/android/cooklang-find-android"

          cat > "${ANDROID_DIR}/settings.gradle.kts" << 'EOF'
          pluginManagement {
              repositories {
                  google()
                  mavenCentral()
                  gradlePluginPortal()
              }
          }
          dependencyResolutionManagement {
              repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
              repositories {
                  google()
                  mavenCentral()
              }
          }
          rootProject.name = "cooklang-find-android"
          EOF

          cat > "${ANDROID_DIR}/build.gradle.kts" << EOF
          plugins {
              id("com.android.library") version "8.2.0"
              id("org.jetbrains.kotlin.android") version "1.9.22"
              id("maven-publish")
          }

          group = "org.cooklang"
          version = "${VERSION}"

          android {
              namespace = "org.cooklang.find"
              compileSdk = 34

              defaultConfig {
                  minSdk = 21
                  testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
                  consumerProguardFiles("consumer-rules.pro")

                  aarMetadata {
                      minCompileSdk = 21
                  }
              }

              buildTypes {
                  release {
                      isMinifyEnabled = false
                      proguardFiles(
                          getDefaultProguardFile("proguard-android-optimize.txt"),
                          "proguard-rules.pro"
                      )
                  }
              }
              compileOptions {
                  sourceCompatibility = JavaVersion.VERSION_1_8
                  targetCompatibility = JavaVersion.VERSION_1_8
              }
              kotlinOptions {
                  jvmTarget = "1.8"
              }
              sourceSets {
                  getByName("main") {
                      jniLibs.srcDirs("src/main/jniLibs")
                  }
              }

              publishing {
                  singleVariant("release") {
                      withSourcesJar()
                  }
              }
          }

          dependencies {
              implementation("net.java.dev.jna:jna:5.14.0@aar")
              implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
              implementation("androidx.annotation:annotation:1.7.0")
          }

          publishing {
              publications {
                  register<MavenPublication>("release") {
                      groupId = "org.cooklang"
                      artifactId = "cooklang-find"
                      version = "${VERSION}"

                      afterEvaluate {
                          from(components["release"])
                      }

                      pom {
                          name.set("CooklangFind")
                          description.set("Library for finding and managing Cooklang recipes")
                          url.set("https://github.com/cooklang/cooklang-find")

                          licenses {
                              license {
                                  name.set("MIT License")
                                  url.set("https://opensource.org/licenses/MIT")
                              }
                          }

                          scm {
                              connection.set("scm:git:git://github.com/cooklang/cooklang-find.git")
                              developerConnection.set("scm:git:ssh://github.com/cooklang/cooklang-find.git")
                              url.set("https://github.com/cooklang/cooklang-find")
                          }
                      }
                  }
              }

              repositories {
                  maven {
                      name = "GitHubPackages"
                      url = uri("https://maven.pkg.github.com/cooklang/cooklang-find")
                      credentials {
                          username = System.getenv("GITHUB_ACTOR")
                          password = System.getenv("GITHUB_TOKEN")
                      }
                  }
              }
          }
          EOF

          cat > "${ANDROID_DIR}/gradle.properties" << 'GRADLE_EOF'
          android.useAndroidX=true
          kotlin.code.style=official
          org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
          android.nonTransitiveRClass=true
          GRADLE_EOF

      - name: Publish to GitHub Packages
        working-directory: target/android/cooklang-find-android
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_ACTOR: ${{ github.actor }}
        run: |
          gradle wrapper --gradle-version 8.5
          ./gradlew publish --no-daemon
