# =============================================================================
# Unified Release Workflow - RC and Production
# =============================================================================
#
# Purpose: Single workflow for both RC and production npm releases.
# npm OIDC Trusted Publishing allows only one workflow file per package.
#
# RC path (workflow_dispatch with release_type=rc):
# 1. Validates RC version format and inputs
# 2. Runs full CI pipeline (Jest + ESLint + release builds)
# 3. Creates release branch with version bumps across 5+ files
# 4. Runs iOS + Android E2E tests on the release branch
# 5. Validates Jira fix version exists
# 6. Publishes to npm with --tag rc
# 7. Creates GitHub pre-release + PR to master
# 8. Notifies team via Slack
#
# Production path (PR merge to master OR workflow_dispatch with release_type=production):
# 1. Validates the merge is from a release branch
# 2. Publishes to npm with the `latest` tag
# 3. Verifies the package is live on npm (retry loop, max 120s)
# 4. Creates a GitHub release with release notes
# 5. Fetches Jira tickets for the fix version
# 6. Notifies team via Slack
#
# =============================================================================

name: Release

on:
  pull_request:
    types:
      - closed
    branches:
      - master

  workflow_dispatch:
    inputs:
      release_type:
        description: 'Release type'
        required: true
        type: choice
        options:
          - rc
          - production
      rn_version:
        description: 'Plugin version (e.g., 6.18.0-rc1 for RC, 6.18.0 for production)'
        required: true
        type: string
      ios_sdk_version:
        description: 'iOS native AppsFlyer SDK version (e.g., 6.18.0) — RC only'
        required: false
        type: string
      android_sdk_version:
        description: 'Android native AppsFlyer SDK version (e.g., 6.18.0) — RC only'
        required: false
        type: string
      base_branch:
        description: 'Base branch to create the release branch from — RC only'
        required: false
        default: development
        type: string
      pc_version:
        description: 'PurchaseConnector iOS version override (leave empty to auto-fetch) — RC only'
        required: false
        default: ''
        type: string
      skip_unit:
        description: 'Skip unit tests and linting — RC only'
        required: false
        type: boolean
        default: false
      skip_builds:
        description: 'Skip Android + iOS release builds — RC only'
        required: false
        type: boolean
        default: false
      skip_e2e:
        description: 'Skip E2E iOS + Android jobs — RC only'
        required: false
        type: boolean
        default: false
      dry_run:
        description: 'Do not publish to npm'
        required: false
        type: boolean
        default: true

concurrency:
  group: release-${{ github.workflow }}-${{ inputs.release_type || 'production' }}
  cancel-in-progress: false

jobs:
  # ===========================================================================
  # Job 0: Route to RC or Production path
  # ===========================================================================

  determine-release-type:
    name: Determine Release Type
    runs-on: ubuntu-latest
    outputs:
      release_type: ${{ steps.route.outputs.release_type }}
      is_valid_trigger: ${{ steps.route.outputs.is_valid_trigger }}
    steps:
      - name: Route release
        id: route
        env:
          EVENT_NAME: ${{ github.event_name }}
          PR_MERGED: ${{ github.event.pull_request.merged }}
          PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
          INPUT_RELEASE_TYPE: ${{ inputs.release_type }}
        run: |
          set -euo pipefail
          if [[ "$EVENT_NAME" == "pull_request" ]]; then
            if [[ "$PR_MERGED" == "true" ]] && [[ "$PR_HEAD_REF" == releases/* ]]; then
              echo "release_type=production" >> "$GITHUB_OUTPUT"
              echo "is_valid_trigger=true" >> "$GITHUB_OUTPUT"
              echo "PR merged from release branch — production path"
            else
              echo "release_type=none" >> "$GITHUB_OUTPUT"
              echo "is_valid_trigger=false" >> "$GITHUB_OUTPUT"
              echo "PR not merged or not from release branch — skipping"
            fi
          else
            echo "release_type=$INPUT_RELEASE_TYPE" >> "$GITHUB_OUTPUT"
            echo "is_valid_trigger=true" >> "$GITHUB_OUTPUT"
            echo "Manual dispatch — $INPUT_RELEASE_TYPE path"
          fi

  # ===========================================================================
  # RC Job 1: Validate RC Inputs & Compute Branch
  # ===========================================================================

  validate-rc:
    name: Validate RC Inputs & Compute Branch
    runs-on: ubuntu-latest
    needs: [determine-release-type]
    if: needs.determine-release-type.outputs.release_type == 'rc'

    outputs:
      version: ${{ steps.compute.outputs.version }}
      base_version: ${{ steps.compute.outputs.base_version }}
      is_rc: ${{ steps.compute.outputs.is_rc }}
      is_valid: ${{ steps.compute.outputs.is_valid }}
      base_branch: ${{ steps.compute.outputs.base_branch }}
      release_branch: ${{ steps.compute.outputs.release_branch }}
      ios_sdk_version: ${{ steps.compute.outputs.ios_sdk_version }}
      android_sdk_version: ${{ steps.compute.outputs.android_sdk_version }}
      is_dry_run: ${{ steps.dry-run.outputs.value }}

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

      - name: Resolve dry_run
        id: dry-run
        env:
          EVENT_NAME: ${{ github.event_name }}
          DISPATCH_DRY: ${{ github.event.inputs.dry_run }}
        run: |
          set -euo pipefail
          case "$EVENT_NAME" in
            workflow_dispatch)
              if [[ "$DISPATCH_DRY" == "true" ]]; then
                echo "value=true" >> "$GITHUB_OUTPUT"
              else
                echo "value=false" >> "$GITHUB_OUTPUT"
              fi
              ;;
            *)
              echo "value=false" >> "$GITHUB_OUTPUT"
              ;;
          esac

      - name: Validate and compute
        id: compute
        env:
          VERSION: ${{ github.event.inputs.rn_version }}
          IOS_VER: ${{ github.event.inputs.ios_sdk_version }}
          AND_VER: ${{ github.event.inputs.android_sdk_version }}
          BASE_BRANCH_INPUT: ${{ github.event.inputs.base_branch }}
        run: |
          set -euo pipefail

          if [[ -z "$VERSION" || -z "$IOS_VER" || -z "$AND_VER" ]]; then
            echo "Missing required inputs"; exit 1
          fi

          # RN version format: X.Y.Z-rcN (no +build)
          if [[ ! $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+$ ]]; then
            echo "rn_version must be X.Y.Z-rcN (e.g., 6.18.0-rc1)"; exit 1
          fi
          if [[ ! $IOS_VER =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "ios_sdk_version must be X.Y.Z"; exit 1
          fi
          if [[ ! $AND_VER =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "android_sdk_version must be X.Y.Z"; exit 1
          fi

          # Compute base version (remove -rcN)
          BASE_VERSION=$(echo "$VERSION" | sed 's/-rc[0-9]*$//')

          MAJOR_MINOR=$(echo "$BASE_VERSION" | grep -oE '^[0-9]+\.[0-9]+')
          MAJOR=$(echo "$BASE_VERSION" | grep -oE '^[0-9]+')
          RELEASE_BRANCH="releases/${MAJOR}.x.x/${MAJOR_MINOR}.x/${VERSION}"

          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT
          echo "is_rc=true" >> $GITHUB_OUTPUT
          echo "is_valid=true" >> $GITHUB_OUTPUT
          echo "base_branch=$BASE_BRANCH_INPUT" >> $GITHUB_OUTPUT
          echo "release_branch=$RELEASE_BRANCH" >> $GITHUB_OUTPUT
          echo "ios_sdk_version=$IOS_VER" >> $GITHUB_OUTPUT
          echo "android_sdk_version=$AND_VER" >> $GITHUB_OUTPUT

  # ===========================================================================
  # RC Job 2: Lint, Test & Build (reusable)
  # ===========================================================================

  run-ci:
    name: Lint, Test & Build
    needs: [determine-release-type, validate-rc]
    if: >-
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.validate-rc.outputs.is_valid == 'true'
    uses: ./.github/workflows/lint-test-build.yml
    with:
      skip_unit: ${{ github.event.inputs.skip_unit == 'true' }}
      skip_builds: ${{ github.event.inputs.skip_builds == 'true' }}
    secrets: inherit

  # ===========================================================================
  # RC Job 3: Create/Update Release Branch and Apply Changes
  # ===========================================================================

  prepare-branch:
    name: Create Release Branch & Apply Changes
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-rc]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.validate-rc.outputs.is_valid == 'true'
    outputs:
      release_branch: ${{ steps.push.outputs.release_branch }}
    steps:
      - name: Checkout base branch
        uses: actions/checkout@v5
        with:
          ref: ${{ needs.validate-rc.outputs.base_branch }}
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: '20'

      - name: Create release branch
        id: branch
        run: |
          set -e
          REL_BRANCH="${{ needs.validate-rc.outputs.release_branch }}"
          echo "Target release branch: $REL_BRANCH"
          if git ls-remote --exit-code --heads origin "$REL_BRANCH" >/dev/null 2>&1; then
            echo "Branch already exists on remote. Checking it out."
            git fetch origin "$REL_BRANCH":"$REL_BRANCH"
            git checkout "$REL_BRANCH"
          else
            git checkout -b "$REL_BRANCH"
          fi

      - name: Update package.json version
        env:
          VERSION: ${{ needs.validate-rc.outputs.version }}
        run: |
          echo "Setting package.json version to $VERSION"
          npm version "$VERSION" --no-git-tag-version
          grep '"version"' package.json

      - name: Update Android SDK fallback in build.gradle
        env:
          AND_VER: ${{ needs.validate-rc.outputs.android_sdk_version }}
        run: |
          sed -i.bak "s/af-android-sdk:\${safeExtGet('appsflyerVersion', '[^']*')}/af-android-sdk:\${safeExtGet('appsflyerVersion', '${AND_VER}')}/" android/build.gradle
          rm -f android/build.gradle.bak
          grep "af-android-sdk:" android/build.gradle

      - name: Update iOS SDK deps in podspec
        env:
          IOS_VER: ${{ needs.validate-rc.outputs.ios_sdk_version }}
          PC_VER_INPUT: ${{ github.event.inputs.pc_version }}
        run: |
          # AppsFlyerFramework (default)
          sed -i.bak "s/'AppsFlyerFramework', '[^']*'/'AppsFlyerFramework', '${IOS_VER}'/" react-native-appsflyer.podspec
          # AppsFlyerFramework/Strict
          sed -i.bak "s|'AppsFlyerFramework/Strict', '[^']*'|'AppsFlyerFramework/Strict', '${IOS_VER}'|" react-native-appsflyer.podspec

          # PurchaseConnector (conditional dep, has its own version)
          if grep -q "PurchaseConnector" react-native-appsflyer.podspec; then
            if [[ -n "${PC_VER_INPUT:-}" ]]; then
              PC_VER="$PC_VER_INPUT"
              echo "Using manual PurchaseConnector version override: $PC_VER"
            else
              PC_VER=$(curl -s "https://api.github.com/repos/AppsFlyerSDK/appsflyer-apple-purchase-connector/releases/latest" | jq -r '.tag_name')
              if [[ -n "$PC_VER" && "$PC_VER" != "null" ]]; then
                echo "Auto-fetched PurchaseConnector version: $PC_VER"
              fi
            fi
            if [[ -z "$PC_VER" || "$PC_VER" == "null" ]]; then
              echo "::error::Could not fetch latest PurchaseConnector version and no pc_version input provided."
              exit 1
            fi
            sed -i.bak "s/'PurchaseConnector', '[^']*'/'PurchaseConnector', '${PC_VER}'/" react-native-appsflyer.podspec
          fi

          rm -f react-native-appsflyer.podspec.bak
          echo "Updated podspec lines:"
          grep -n "AppsFlyerFramework\|PurchaseConnector" react-native-appsflyer.podspec || true

      - name: Update plugin version constants
        env:
          VERSION: ${{ needs.validate-rc.outputs.version }}
        run: |
          echo "Updating PLUGIN_VERSION constants to: $VERSION"

          # Android - RNAppsFlyerConstants.java
          sed -i.bak "s/PLUGIN_VERSION = \"[^\"]*\"/PLUGIN_VERSION = \"${VERSION}\"/" android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java
          rm -f android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java.bak
          echo "Android:" && grep "PLUGIN_VERSION" android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java

          # iOS - RNAppsFlyer.h
          sed -i.bak "s/kAppsFlyerPluginVersion[[:space:]]*= @\"[^\"]*\"/kAppsFlyerPluginVersion      = @\"${VERSION}\"/" ios/RNAppsFlyer.h
          rm -f ios/RNAppsFlyer.h.bak
          echo "iOS:" && grep "kAppsFlyerPluginVersion" ios/RNAppsFlyer.h

      - name: Update README SDK version badges
        env:
          IOS_VER: ${{ needs.validate-rc.outputs.ios_sdk_version }}
          AND_VER: ${{ needs.validate-rc.outputs.android_sdk_version }}
        run: |
          sed -i.bak -E "s/Android AppsFlyer SDK \*\*v[0-9.]+\*\*/Android AppsFlyer SDK **v${AND_VER}**/" README.md
          sed -i.bak -E "s/iOS AppsFlyer SDK \*\*v[0-9.]+\*\*/iOS AppsFlyer SDK **v${IOS_VER}**/" README.md
          rm -f README.md.bak
          grep -n "AppsFlyer SDK \*\*v" README.md

      - name: Update CHANGELOG.md
        env:
          VERSION: ${{ needs.validate-rc.outputs.version }}
          IOS_VER: ${{ needs.validate-rc.outputs.ios_sdk_version }}
          AND_VER: ${{ needs.validate-rc.outputs.android_sdk_version }}
        run: |
          CHANGELOG_ENTRY="## ${VERSION}\n Release date: *$(date +%Y-%m-%d)*\n\n### Changes\n- Android SDK ${AND_VER}\n- iOS SDK ${IOS_VER}\n- TODO: Add specific changes before merging\n"
          printf '%b\n' "$CHANGELOG_ENTRY" | cat - CHANGELOG.md > CHANGELOG.tmp && mv CHANGELOG.tmp CHANGELOG.md
          head -10 CHANGELOG.md

      - name: Commit & push changes
        id: push
        env:
          VERSION: ${{ needs.validate-rc.outputs.version }}
          IOS_VER: ${{ needs.validate-rc.outputs.ios_sdk_version }}
          AND_VER: ${{ needs.validate-rc.outputs.android_sdk_version }}
        run: |
          set -e
          REL_BRANCH='${{ needs.validate-rc.outputs.release_branch }}'
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git config user.name "github-actions[bot]"
          if [[ -n $(git status -s) ]]; then
            git add -f package.json react-native-appsflyer.podspec README.md CHANGELOG.md \
              ios/RNAppsFlyer.h \
              android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java \
              android/build.gradle
            git commit -m "chore: prepare RC ${VERSION} (iOS ${IOS_VER}, Android ${AND_VER})"
            git push --set-upstream origin "$REL_BRANCH"
          else
            echo "No changes to commit"
            if ! git ls-remote --exit-code --heads origin "$REL_BRANCH" >/dev/null 2>&1; then
              git push --set-upstream origin "$REL_BRANCH"
            fi
          fi
          echo "release_branch=$REL_BRANCH" >> $GITHUB_OUTPUT

  # ===========================================================================
  # RC Job 4: E2E iOS
  # ===========================================================================

  run-e2e-ios:
    name: RC-E2E iOS
    needs: [determine-release-type, validate-rc, prepare-branch]
    if: >-
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.validate-rc.outputs.is_valid == 'true' &&
      github.event.inputs.skip_e2e != 'true'
    uses: ./.github/workflows/ios-e2e.yml
    with:
      ref: ${{ needs.prepare-branch.outputs.release_branch }}
    secrets: inherit

  # ===========================================================================
  # RC Job 5: E2E Android
  # ===========================================================================

  run-e2e-android:
    name: RC-E2E Android
    needs: [determine-release-type, validate-rc, prepare-branch]
    if: >-
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.validate-rc.outputs.is_valid == 'true' &&
      github.event.inputs.skip_e2e != 'true'
    uses: ./.github/workflows/android-e2e.yml
    with:
      ref: ${{ needs.prepare-branch.outputs.release_branch }}
    secrets: inherit

  # ===========================================================================
  # RC Job 6: Pre-publish gate
  # ===========================================================================

  pre-publish-gate:
    name: Pre-publish Gate
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-rc, run-ci, run-e2e-ios, run-e2e-android]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.validate-rc.outputs.is_valid == 'true'
    outputs:
      passed: ${{ steps.aggregate.outputs.passed }}
      ci_result: ${{ steps.aggregate.outputs.ci_result }}
      e2e_ios_result: ${{ steps.aggregate.outputs.e2e_ios_result }}
      e2e_android_result: ${{ steps.aggregate.outputs.e2e_android_result }}
    steps:
      - name: Aggregate pre-publish results
        id: aggregate
        env:
          CI_RESULT: ${{ needs.run-ci.result }}
          E2E_IOS_RESULT: ${{ needs.run-e2e-ios.result }}
          E2E_ANDROID_RESULT: ${{ needs.run-e2e-android.result }}
        run: |
          set -euo pipefail
          echo "Lint, Test & Build : $CI_RESULT"
          echo "RC-E2E iOS         : $E2E_IOS_RESULT"
          echo "RC-E2E Android     : $E2E_ANDROID_RESULT"

          ci_ok=false
          ios_ok=false
          android_ok=false

          if [[ "$CI_RESULT" == "success" || "$CI_RESULT" == "skipped" ]]; then
            ci_ok=true
          fi
          if [[ "$E2E_IOS_RESULT" == "success" || "$E2E_IOS_RESULT" == "skipped" ]]; then
            ios_ok=true
          fi
          if [[ "$E2E_ANDROID_RESULT" == "success" || "$E2E_ANDROID_RESULT" == "skipped" ]]; then
            android_ok=true
          fi

          {
            echo "ci_result=$CI_RESULT"
            echo "e2e_ios_result=$E2E_IOS_RESULT"
            echo "e2e_android_result=$E2E_ANDROID_RESULT"
          } >> "$GITHUB_OUTPUT"

          if $ci_ok && $ios_ok && $android_ok; then
            echo "passed=true" >> "$GITHUB_OUTPUT"
            echo "Pre-publish gate passed"
            exit 0
          fi

          echo "passed=false" >> "$GITHUB_OUTPUT"
          echo "Pre-publish gate failed"
          $ci_ok      || echo "  - Lint, Test & Build did not pass ($CI_RESULT)"
          $ios_ok     || echo "  - RC-E2E iOS did not pass ($E2E_IOS_RESULT)"
          $android_ok || echo "  - RC-E2E Android did not pass ($E2E_ANDROID_RESULT)"
          exit 1

  # ===========================================================================
  # RC Job 7: Validate Jira fix version
  # ===========================================================================

  validate-jira:
    name: Validate Jira Fix Version
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-rc, pre-publish-gate]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.pre-publish-gate.result == 'success' &&
      needs.pre-publish-gate.outputs.passed == 'true'
    steps:
      - name: Verify Jira fix version exists
        env:
          CI_JIRA_EMAIL: ${{ secrets.CI_JIRA_EMAIL }}
          CI_JIRA_TOKEN: ${{ secrets.CI_JIRA_TOKEN }}
          CI_JIRA_DOMAIN: ${{ secrets.CI_JIRA_DOMAIN }}
          BASE_VERSION: ${{ needs.validate-rc.outputs.base_version }}
        run: |
          set -euo pipefail
          JIRA_FIX_VERSION="React Native SDK v${BASE_VERSION}"
          JIRA_DOMAIN="${CI_JIRA_DOMAIN:-appsflyer.atlassian.net}"

          echo "Looking for Jira fix version: $JIRA_FIX_VERSION"

          if [[ -z "${CI_JIRA_EMAIL:-}" || -z "${CI_JIRA_TOKEN:-}" ]]; then
            echo "::warning::Jira credentials not configured, skipping validation"
            exit 0
          fi

          RESPONSE=$(curl -s -u "${CI_JIRA_EMAIL}:${CI_JIRA_TOKEN}" \
            "https://${JIRA_DOMAIN}/rest/api/3/project/SDKRC/versions" \
            | jq -r ".[] | select(.name == \"$JIRA_FIX_VERSION\") | .name")

          if [[ -z "$RESPONSE" ]]; then
            echo "::error::Jira fix version '$JIRA_FIX_VERSION' not found. Create it before publishing."
            exit 1
          fi
          echo "Jira fix version found: $RESPONSE"

  # ===========================================================================
  # Production Job 1: Validate Production Release
  # ===========================================================================

  validate-production:
    name: Validate Production Release
    runs-on: ubuntu-latest
    needs: [determine-release-type]
    if: >-
      needs.determine-release-type.outputs.release_type == 'production' &&
      needs.determine-release-type.outputs.is_valid_trigger == 'true'

    outputs:
      version: ${{ steps.get-version.outputs.version }}
      is_valid: ${{ steps.validate.outputs.is_valid }}
      is_dry_run: ${{ steps.dry-run.outputs.value }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 20

      - name: Resolve dry_run across trigger paths
        id: dry-run
        env:
          EVENT_NAME: ${{ github.event_name }}
          DISPATCH_DRY: ${{ github.event.inputs.dry_run }}
        run: |
          set -euo pipefail
          if [[ "$EVENT_NAME" == "workflow_dispatch" && "$DISPATCH_DRY" == "true" ]]; then
            echo "value=true" >> "$GITHUB_OUTPUT"
          else
            echo "value=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Validate release source
        id: validate
        env:
          EVENT_NAME: ${{ github.event_name }}
          PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
        run: |
          if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
            echo "Manual run - skipping branch validation"
            echo "is_valid=true" >> "$GITHUB_OUTPUT"
          else
            SOURCE_BRANCH="$PR_HEAD_REF"
            echo "Source branch: $SOURCE_BRANCH"

            if [[ $SOURCE_BRANCH =~ ^releases/ ]]; then
              echo "Valid release branch: $SOURCE_BRANCH"
              echo "is_valid=true" >> "$GITHUB_OUTPUT"
            else
              echo "::error::Not a release branch: $SOURCE_BRANCH"
              echo "is_valid=false" >> "$GITHUB_OUTPUT"
              exit 1
            fi
          fi

      - name: Get version from package.json
        id: get-version
        env:
          EVENT_NAME: ${{ github.event_name }}
          INPUT_VERSION: ${{ github.event.inputs.rn_version }}
        run: |
          if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
            VERSION="$INPUT_VERSION"
            echo "Using provided version: $VERSION"
          else
            VERSION=$(node -p "require('./package.json').version")
            echo "Extracted version from package.json: $VERSION"
          fi

          # Validate version format (X.Y.Z, no -rc suffix for production)
          if [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "Valid production version format: $VERSION"
            echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          else
            echo "::error::Invalid production version format: $VERSION (expected X.Y.Z)"
            exit 1
          fi

      - name: Check if tag already exists
        env:
          VERSION: ${{ steps.get-version.outputs.version }}
          DRY_RUN: ${{ steps.dry-run.outputs.value }}
        run: |
          git fetch --tags
          if git rev-parse "v$VERSION" >/dev/null 2>&1 || git rev-parse "$VERSION" >/dev/null 2>&1; then
            echo "::warning::Tag for $VERSION already exists"
            if [[ "$DRY_RUN" != "true" ]]; then
              echo "::error::Cannot create duplicate release"
              exit 1
            fi
          fi
          echo "Tag $VERSION does not exist - safe to proceed"

  # ===========================================================================
  # Shared: Publish to npm (RC with --tag rc, Production with latest)
  # ===========================================================================

  publish-to-npm:
    name: Publish to npm
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-rc, validate-production, prepare-branch, pre-publish-gate, validate-jira]
    if: >-
      !cancelled() &&
      (
        (needs.determine-release-type.outputs.release_type == 'rc' &&
         needs.pre-publish-gate.result == 'success' &&
         needs.pre-publish-gate.outputs.passed == 'true' &&
         (needs.validate-jira.result == 'success' || needs.validate-jira.result == 'skipped'))
        ||
        (needs.determine-release-type.outputs.release_type == 'production' &&
         needs.validate-production.result == 'success' &&
         needs.validate-production.outputs.is_valid == 'true')
      )
    permissions:
      contents: read
      id-token: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 0
          ref: ${{ needs.determine-release-type.outputs.release_type == 'rc' && needs.prepare-branch.outputs.release_branch || '' }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: '24'
          registry-url: 'https://registry.npmjs.org'
          package-manager-cache: false

      - name: Install dependencies
        run: npm install

      - name: Verify version consistency
        env:
          RELEASE_TYPE: ${{ needs.determine-release-type.outputs.release_type }}
          RC_VERSION: ${{ needs.validate-rc.outputs.version }}
          PROD_VERSION: ${{ needs.validate-production.outputs.version }}
        run: |
          ACTUAL=$(node -p "require('./package.json').version")
          if [[ "$RELEASE_TYPE" == "rc" ]]; then
            EXPECTED="$RC_VERSION"
          else
            EXPECTED="$PROD_VERSION"
          fi
          if [[ "$ACTUAL" != "$EXPECTED" ]]; then
            echo "::error::Version mismatch: package.json has '$ACTUAL' but expected '$EXPECTED'"
            exit 1
          fi
          echo "Version consistent: $ACTUAL"

      - name: Validate package (dry-run)
        run: npm pack --dry-run

      - name: Determine publish parameters
        id: publish-params
        env:
          RELEASE_TYPE: ${{ needs.determine-release-type.outputs.release_type }}
          RC_DRY_RUN: ${{ needs.validate-rc.outputs.is_dry_run }}
          PROD_DRY_RUN: ${{ needs.validate-production.outputs.is_dry_run }}
        run: |
          if [[ "$RELEASE_TYPE" == "rc" ]]; then
            echo "npm_tag=rc" >> "$GITHUB_OUTPUT"
            echo "is_dry_run=${RC_DRY_RUN:-false}" >> "$GITHUB_OUTPUT"
          else
            echo "npm_tag=latest" >> "$GITHUB_OUTPUT"
            echo "is_dry_run=${PROD_DRY_RUN:-false}" >> "$GITHUB_OUTPUT"
          fi

      - name: Dry-run — skipping publish
        if: steps.publish-params.outputs.is_dry_run == 'true'
        run: |
          echo "DRY RUN — would publish $(node -p "require('./package.json').version") to npm"
          npm pack --dry-run

      - name: Publish to npm
        if: steps.publish-params.outputs.is_dry_run != 'true'
        env:
          NODE_AUTH_TOKEN: ''
        run: |
          VERSION=$(node -p "require('./package.json').version")
          TAG="${{ steps.publish-params.outputs.npm_tag }}"
          echo "Publishing $VERSION to npm with tag: $TAG"
          if [[ "$TAG" == "rc" ]]; then
            npm publish --tag rc --provenance
          else
            npm publish --provenance
          fi
          echo "Published $VERSION to npm"

      - name: Verify publication (production only)
        if: >-
          needs.determine-release-type.outputs.release_type == 'production' &&
          steps.publish-params.outputs.is_dry_run != 'true'
        env:
          VERSION: ${{ needs.validate-production.outputs.version }}
        run: |
          MAX_WAIT=120
          POLL=15
          ELAPSED=0
          while (( ELAPSED < MAX_WAIT )); do
            if npm view "react-native-appsflyer@$VERSION" version 2>/dev/null | grep -Fxq "$VERSION"; then
              echo "Verified: $VERSION is live on npm"
              break
            fi
            echo "Waiting for npm propagation (${ELAPSED}s / ${MAX_WAIT}s)..."
            sleep "$POLL"
            ELAPSED=$(( ELAPSED + POLL ))
          done
          if (( ELAPSED >= MAX_WAIT )); then
            echo "::warning::npm propagation exceeded ${MAX_WAIT}s --- verify manually on npmjs.com"
          fi

  # ===========================================================================
  # RC Job 8: Create Pre-Release Tag
  # ===========================================================================

  create-prerelease:
    name: Create Pre-Release
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-rc, prepare-branch, publish-to-npm]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.validate-rc.outputs.is_rc == 'true' &&
      needs.publish-to-npm.result == 'success'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 0
          ref: ${{ needs.prepare-branch.outputs.release_branch }}

      - name: Generate release notes
        id: release-notes
        env:
          VERSION: ${{ needs.validate-rc.outputs.version }}
          IOS_VER: ${{ needs.validate-rc.outputs.ios_sdk_version }}
          AND_VER: ${{ needs.validate-rc.outputs.android_sdk_version }}
        run: |
          cat > release_notes.md << EOF
          # AppsFlyer React Native Plugin - Release Candidate $VERSION

          ## Release Candidate for Testing

          This is a pre-release version for QA testing. Do not use in production.

          ## Testing Instructions

          \`\`\`bash
          npm install react-native-appsflyer@${VERSION} --save
          \`\`\`

          ## SDK Versions

          - Android AppsFlyer SDK: ${AND_VER}
          - iOS AppsFlyer SDK: ${IOS_VER}

          ---

          **Note**: This is a pre-release and should not be used in production applications.
          EOF

      - name: Create GitHub Pre-Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.validate-rc.outputs.version }}
          name: Release Candidate ${{ needs.validate-rc.outputs.version }}
          body_path: release_notes.md
          draft: false
          prerelease: true
          generate_release_notes: false
          token: ${{ secrets.GITHUB_TOKEN }}

  # ===========================================================================
  # RC Job 9: Open PR to master
  # ===========================================================================

  open-pr:
    name: Open PR to master
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-rc, prepare-branch, publish-to-npm]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'rc' &&
      needs.publish-to-npm.result == 'success'
    steps:
      - name: Checkout
        uses: actions/checkout@v5
        with:
          fetch-depth: 0
          ref: ${{ needs.prepare-branch.outputs.release_branch }}

      - name: Create or update PR
        uses: actions/github-script@v7
        with:
          script: |
            const version = '${{ needs.validate-rc.outputs.base_version }}';
            const rcVersion = '${{ needs.validate-rc.outputs.version }}';
            const head = '${{ needs.prepare-branch.outputs.release_branch }}';
            const base = 'master';
            const androidVersion = '${{ needs.validate-rc.outputs.android_sdk_version }}';
            const iosVersion = '${{ needs.validate-rc.outputs.ios_sdk_version }}';

            const { data: prs } = await github.rest.pulls.list({
              owner: context.repo.owner,
              repo: context.repo.repo,
              state: 'open',
              head: `${context.repo.owner}:${head}`
            });

            const body = [
              `### Release ${version}`,
              '',
              `- Android SDK: ${androidVersion}`,
              `- iOS SDK: ${iosVersion}`,
              '',
              '```bash',
              `npm install react-native-appsflyer@${rcVersion} --save`,
              '```',
              '',
              'This PR was opened by the RC workflow.'
            ].join('\n');

            if (prs.length > 0) {
              const pr = prs[0];
              await github.rest.pulls.update({
                owner: context.repo.owner,
                repo: context.repo.repo,
                pull_number: pr.number,
                title: `Release ${version}`,
                body
              });
              core.setOutput('pr_number', pr.number);
            } else {
              const { data: pr } = await github.rest.pulls.create({
                owner: context.repo.owner,
                repo: context.repo.repo,
                head,
                base,
                title: `Release ${version}`,
                body,
                maintainer_can_modify: true
              });
              core.setOutput('pr_number', pr.number);
            }

  # ===========================================================================
  # Production Job 2: Create GitHub Release
  # ===========================================================================

  create-github-release:
    name: Create GitHub Release
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-production, publish-to-npm]
    if: >-
      needs.determine-release-type.outputs.release_type == 'production' &&
      needs.publish-to-npm.result == 'success' &&
      needs.validate-production.outputs.is_dry_run != 'true'

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 0

      - name: Extract release notes from CHANGELOG
        id: changelog
        env:
          VERSION: ${{ needs.validate-production.outputs.version }}
        run: |
          echo "Extracting release notes for version $VERSION from CHANGELOG.md"

          if [ -f "CHANGELOG.md" ]; then
            RELEASE_NOTES=$(awk "/## $VERSION/,/^## [0-9]/" CHANGELOG.md | sed '1d;$d')

            if [ -z "$RELEASE_NOTES" ]; then
              echo "::warning::Could not find release notes for $VERSION in CHANGELOG.md"
              RELEASE_NOTES="Release version $VERSION. See [CHANGELOG.md](CHANGELOG.md) for details."
            fi
          else
            RELEASE_NOTES="Release version $VERSION."
          fi

          echo "$RELEASE_NOTES" > release_notes.md

      - name: Build release notes
        env:
          VERSION: ${{ needs.validate-production.outputs.version }}
          REPO: ${{ github.repository }}
        run: |
          cat > final_release_notes.md << EOF
          # AppsFlyer React Native Plugin v$VERSION

          ## Installation

          \`\`\`bash
          npm install react-native-appsflyer@$VERSION
          \`\`\`

          Then for iOS:
          \`\`\`bash
          cd ios && pod install
          \`\`\`

          ## Changes in This Release

          $(cat release_notes.md)

          ## Documentation

          - [Installation Guide](https://github.com/$REPO/blob/master/Docs/Installation.md)
          - [API Documentation](https://github.com/$REPO/blob/master/Docs/API.md)
          - [Deep Linking Guide](https://github.com/$REPO/blob/master/Docs/DeepLink.md)
          - [Expo Integration](https://github.com/$REPO/blob/master/Docs/ExpoIntegration.md)

          ## Links

          - [npm Package](https://www.npmjs.com/package/react-native-appsflyer/v/$VERSION)
          - [GitHub Repository](https://github.com/$REPO)
          - [AppsFlyer Developer Hub](https://dev.appsflyer.com/)

          ## Support

          For issues and questions, please contact <support@appsflyer.com>
          EOF

      - name: Create GitHub Release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          VERSION: ${{ needs.validate-production.outputs.version }}
        run: |
          gh release create "v$VERSION" \
            --title "v$VERSION" \
            --notes-file final_release_notes.md \
            --latest

  # ===========================================================================
  # RC Notify Team
  # ===========================================================================

  notify-team-rc:
    name: Notify Team (RC)
    runs-on: ubuntu-latest
    needs:
      - determine-release-type
      - validate-rc
      - prepare-branch
      - run-ci
      - run-e2e-ios
      - run-e2e-android
      - pre-publish-gate
      - validate-jira
      - publish-to-npm
      - create-prerelease
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'rc'

    steps:
      - name: Determine status and failed stage
        id: status
        env:
          VALIDATE_RESULT: ${{ needs.validate-rc.result }}
          PREPARE_RESULT: ${{ needs.prepare-branch.result }}
          GATE_RESULT: ${{ needs.pre-publish-gate.result }}
          JIRA_RESULT: ${{ needs.validate-jira.result }}
          PUBLISH_RESULT: ${{ needs.publish-to-npm.result }}
          PRERELEASE_RESULT: ${{ needs.create-prerelease.result }}
        run: |
          set -euo pipefail
          ok() { [[ "$1" == "success" || "$1" == "skipped" ]]; }

          if [[ "$VALIDATE_RESULT" == "success" \
             && "$PREPARE_RESULT"   == "success" \
             && "$GATE_RESULT"      == "success" ]] \
             && ok "$JIRA_RESULT" \
             && ok "$PUBLISH_RESULT" \
             && ok "$PRERELEASE_RESULT"; then
            echo "success=true" >> "$GITHUB_OUTPUT"
            echo "failed_stage=" >> "$GITHUB_OUTPUT"
            exit 0
          fi
          echo "success=false" >> "$GITHUB_OUTPUT"
          if [[ "$VALIDATE_RESULT" != "success" ]]; then
            echo "failed_stage=validate-rc" >> "$GITHUB_OUTPUT"
          elif [[ "$PREPARE_RESULT" != "success" ]]; then
            echo "failed_stage=prepare-branch" >> "$GITHUB_OUTPUT"
          elif [[ "$GATE_RESULT" != "success" ]]; then
            echo "failed_stage=pre-publish-gate" >> "$GITHUB_OUTPUT"
          elif ! ok "$JIRA_RESULT"; then
            echo "failed_stage=validate-jira" >> "$GITHUB_OUTPUT"
          elif ! ok "$PUBLISH_RESULT"; then
            echo "failed_stage=publish-to-npm" >> "$GITHUB_OUTPUT"
          else
            echo "failed_stage=create-prerelease" >> "$GITHUB_OUTPUT"
          fi

      - name: Format pre-publish leg results
        id: legs
        env:
          CI_RESULT: ${{ needs.run-ci.result }}
          E2E_IOS_RESULT: ${{ needs.run-e2e-ios.result }}
          E2E_ANDROID_RESULT: ${{ needs.run-e2e-android.result }}
        run: |
          set -euo pipefail
          icon_for() {
            local kind="$1" result="$2"
            case "$result" in
              success) echo ":white_check_mark:" ;;
              skipped)
                if [[ "$kind" == "ci" ]]; then echo ":fast_forward:"; else echo ":x:"; fi ;;
              failure)   echo ":x:" ;;
              cancelled) echo ":no_entry_sign:" ;;
              *)         echo ":grey_question:" ;;
            esac
          }
          CI_ICON=$(icon_for ci "$CI_RESULT")
          IOS_ICON=$(icon_for e2e "$E2E_IOS_RESULT")
          ANDROID_ICON=$(icon_for e2e "$E2E_ANDROID_RESULT")
          {
            echo "ci_icon=$CI_ICON"
            echo "ios_icon=$IOS_ICON"
            echo "android_icon=$ANDROID_ICON"
            echo "ci_result=$CI_RESULT"
            echo "e2e_ios_result=$E2E_IOS_RESULT"
            echo "e2e_android_result=$E2E_ANDROID_RESULT"
          } >> "$GITHUB_OUTPUT"

      - name: Checkout release branch
        if: steps.status.outputs.success == 'true'
        uses: actions/checkout@v5
        with:
          fetch-depth: 0
          ref: ${{ needs.prepare-branch.outputs.release_branch }}

      - name: Extract SDK versions and changelog
        id: extract-info
        if: steps.status.outputs.success == 'true'
        run: |
          VERSION="${{ needs.validate-rc.outputs.version }}"

          echo "android_sdk=${{ needs.validate-rc.outputs.android_sdk_version }}" >> $GITHUB_OUTPUT
          echo "ios_sdk=${{ needs.validate-rc.outputs.ios_sdk_version }}" >> $GITHUB_OUTPUT

          # Extract changelog for this version
          if [ -f "CHANGELOG.md" ]; then
            CHANGELOG=$(awk "/## $VERSION/,/^## [0-9]/" CHANGELOG.md | grep "^-" | sed 's/^- //' | head -5)
            if [ -z "$CHANGELOG" ]; then
              CHANGELOG="Check CHANGELOG.md for details"
            fi
          else
            CHANGELOG="Check release notes for details"
          fi

          echo "changelog<<EOF" >> $GITHUB_OUTPUT
          echo "$CHANGELOG" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Fetch Jira tickets
        id: jira-tickets
        if: steps.status.outputs.success == 'true'
        continue-on-error: true
        env:
          CI_JIRA_EMAIL: ${{ secrets.CI_JIRA_EMAIL }}
          CI_JIRA_TOKEN: ${{ secrets.CI_JIRA_TOKEN }}
          CI_JIRA_DOMAIN: ${{ secrets.CI_JIRA_DOMAIN }}
        run: |
          set +e
          VERSION="${{ needs.validate-rc.outputs.version }}"
          BASE_VERSION=$(echo "$VERSION" | sed 's/-rc[0-9]*$//')
          JIRA_FIX_VERSION="React Native SDK v$BASE_VERSION"
          JIRA_DOMAIN="${CI_JIRA_DOMAIN:-appsflyer.atlassian.net}"

          echo "Looking for Jira tickets with fix version: $JIRA_FIX_VERSION"

          if [[ -z "${CI_JIRA_EMAIL:-}" ]] || [[ -z "${CI_JIRA_TOKEN:-}" ]]; then
            echo "Jira credentials not configured"
            echo "tickets=No assigned fix version found" >> $GITHUB_OUTPUT
            exit 0
          fi

          JQL_QUERY="fixVersion=\"${JIRA_FIX_VERSION}\""
          ENCODED_JQL=$(echo "$JQL_QUERY" | jq -sRr @uri)

          RESPONSE=$(curl -s -w "\n%{http_code}" \
            -u "${CI_JIRA_EMAIL}:${CI_JIRA_TOKEN}" \
            -H "Accept: application/json" \
            -H "Content-Type: application/json" \
            "https://${JIRA_DOMAIN}/rest/api/3/search/jql?jql=${ENCODED_JQL}&fields=key,summary&maxResults=20")

          HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
          BODY=$(echo "$RESPONSE" | sed '$d')

          if [[ "$HTTP_CODE" != "200" ]]; then
            echo "Jira API request failed with status $HTTP_CODE"
            echo "tickets=No assigned fix version found" >> $GITHUB_OUTPUT
            exit 0
          fi

          TICKETS=$(echo "$BODY" | jq -r '.issues[]? | "https://'"${JIRA_DOMAIN}"'/browse/\(.key) - \(.fields.summary)"' 2>/dev/null | head -10)

          if [ -z "$TICKETS" ]; then
            echo "tickets=No assigned fix version found" >> $GITHUB_OUTPUT
          else
            echo "tickets<<EOF" >> $GITHUB_OUTPUT
            echo "$TICKETS" >> $GITHUB_OUTPUT
            echo "EOF" >> $GITHUB_OUTPUT
          fi

      - name: Send Slack notification (Success)
        if: steps.status.outputs.success == 'true'
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "<!here>\n:react::react::react::react::react::react::react::react::react::react::react::react:\n\n${{ needs.validate-rc.outputs.is_dry_run == 'true' && ':test_tube: *[DRY RUN]* ' || '' }}*React Native Release Candidate:*\nreact-native-appsflyer: ${{ needs.validate-rc.outputs.version }} ${{ needs.validate-rc.outputs.is_dry_run == 'true' && 'pipeline completed (not published to npm)' || 'is ready for QA testing' }}.\n\n*Pre-publish checks:*\n${{ steps.legs.outputs.ci_icon }} Lint, Test & Build: ${{ steps.legs.outputs.ci_result }}\n${{ steps.legs.outputs.ios_icon }} RC-E2E iOS: ${{ steps.legs.outputs.e2e_ios_result }}\n${{ steps.legs.outputs.android_icon }} RC-E2E Android: ${{ steps.legs.outputs.e2e_android_result }}\n${{ needs.validate-rc.outputs.is_dry_run != 'true' && format('\n*Testing Instructions:*\n```\nnpm install react-native-appsflyer@{0} --save\n```', needs.validate-rc.outputs.version) || '' }}\n\n*Sources:*\n:github: https://github.com/${{ github.repository }}/tree/${{ github.ref_name }}\n:github: Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n${{ needs.validate-rc.outputs.is_dry_run != 'true' && format(':github: Release: https://github.com/{0}/releases/tag/{1}', github.repository, needs.validate-rc.outputs.version) || '' }}\n\n*Changes and fixes:*\n${{ steps.extract-info.outputs.changelog }}\n\n*Linked tickets and issues:*\n${{ steps.jira-tickets.outputs.tickets }}\n\n*Native SDKs:*\n:android: ${{ steps.extract-info.outputs.android_sdk }}\n:apple: ${{ steps.extract-info.outputs.ios_sdk }}\n\n:react::react::react::react::react::react::react::react::react::react::react::react:"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.CI_SLACK_HOOK }}

      - name: Send failure notification
        if: steps.status.outputs.success == 'false'
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "<!here>\n:warning: *${{ needs.validate-rc.outputs.is_dry_run == 'true' && '[DRY RUN] ' || '' }}React Native RC failed at `${{ steps.status.outputs.failed_stage }}`*\n\nVersion: ${{ needs.validate-rc.outputs.version }}\nBranch: ${{ github.ref_name }}\nRun: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\n*Pre-publish checks:*\n${{ steps.legs.outputs.ci_icon }} Lint, Test & Build: ${{ steps.legs.outputs.ci_result }}\n${{ steps.legs.outputs.ios_icon }} RC-E2E iOS: ${{ steps.legs.outputs.e2e_ios_result }}\n${{ steps.legs.outputs.android_icon }} RC-E2E Android: ${{ steps.legs.outputs.e2e_android_result }}\n\n*Downstream stages:*\n- prepare-branch: ${{ needs.prepare-branch.result }}\n- pre-publish-gate: ${{ needs.pre-publish-gate.result }}\n- validate-jira: ${{ needs.validate-jira.result }}\n- publish-to-npm: ${{ needs.publish-to-npm.result }}\n- create-prerelease: ${{ needs.create-prerelease.result }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.CI_SLACK_HOOK }}

  # ===========================================================================
  # Production Notify Team
  # ===========================================================================

  notify-team-production:
    name: Notify Team (Production)
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-production, publish-to-npm, create-github-release]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'production' &&
      needs.validate-production.outputs.is_dry_run != 'true'

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

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 20

      - name: Extract SDK versions and changelog
        id: extract-info
        env:
          VERSION: ${{ needs.validate-production.outputs.version }}
        run: |
          # Extract Android SDK fallback version from build.gradle
          ANDROID_SDK_VERSION=$(grep "af-android-sdk" android/build.gradle | grep -oP "'[0-9][^']*'" | tr -d "'" | head -1)
          echo "android_sdk=$ANDROID_SDK_VERSION" >> "$GITHUB_OUTPUT"

          # Extract iOS SDK version from podspec
          IOS_SDK_VERSION=$(grep "AppsFlyerFramework'" react-native-appsflyer.podspec | grep -oP "'~> \K[^']*" | head -1)
          if [ -z "$IOS_SDK_VERSION" ]; then
            IOS_SDK_VERSION=$(grep "AppsFlyerFramework'" react-native-appsflyer.podspec | grep -oP "'\K[0-9][^']*" | head -1)
          fi
          echo "ios_sdk=$IOS_SDK_VERSION" >> "$GITHUB_OUTPUT"

          # Extract changelog for this version
          if [ -f "CHANGELOG.md" ]; then
            CHANGELOG=$(awk "/## $VERSION/,/^## [0-9]/" CHANGELOG.md | grep "^-" | sed 's/^- /- /' | head -5)
            if [ -z "$CHANGELOG" ]; then
              CHANGELOG="- Check CHANGELOG.md for details"
            fi
          else
            CHANGELOG="- Check release notes for details"
          fi

          echo "changelog<<EOF" >> "$GITHUB_OUTPUT"
          echo "$CHANGELOG" >> "$GITHUB_OUTPUT"
          echo "EOF" >> "$GITHUB_OUTPUT"

      - name: Fetch Jira tickets
        id: jira-tickets
        continue-on-error: true
        env:
          VERSION: ${{ needs.validate-production.outputs.version }}
          CI_JIRA_EMAIL: ${{ secrets.CI_JIRA_EMAIL }}
          CI_JIRA_TOKEN: ${{ secrets.CI_JIRA_TOKEN }}
          CI_JIRA_DOMAIN: ${{ secrets.CI_JIRA_DOMAIN }}
        run: |
          set +e
          JIRA_FIX_VERSION="React Native SDK v$VERSION"

          echo "Looking for Jira tickets with fix version: $JIRA_FIX_VERSION"

          if [[ -z "$CI_JIRA_EMAIL" ]] || [[ -z "$CI_JIRA_TOKEN" ]]; then
            echo "::warning::Jira credentials not configured"
            echo "tickets=No assigned fix version found" >> "$GITHUB_OUTPUT"
            exit 0
          fi

          JIRA_DOMAIN="${CI_JIRA_DOMAIN:-appsflyer.atlassian.net}"

          JQL_QUERY="fixVersion=\"${JIRA_FIX_VERSION}\""
          ENCODED_JQL=$(echo "$JQL_QUERY" | jq -sRr @uri)

          RESPONSE=$(curl -s -w "\n%{http_code}" \
            -u "$CI_JIRA_EMAIL:$CI_JIRA_TOKEN" \
            -H "Accept: application/json" \
            -H "Content-Type: application/json" \
            "https://${JIRA_DOMAIN}/rest/api/3/search/jql?jql=${ENCODED_JQL}&fields=key,summary&maxResults=20")

          HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
          BODY=$(echo "$RESPONSE" | sed '$d')

          if [[ "$HTTP_CODE" != "200" ]]; then
            echo "::warning::Jira API request failed with status $HTTP_CODE"
            echo "tickets=No assigned fix version found" >> "$GITHUB_OUTPUT"
            exit 0
          fi

          TICKETS=$(echo "$BODY" | jq -r '.issues[]? | "- https://'"${JIRA_DOMAIN}"'/browse/\(.key) - \(.fields.summary)"' 2>/dev/null | head -10)

          if [ -z "$TICKETS" ]; then
            echo "No linked tickets found for version: $JIRA_FIX_VERSION"
            echo "tickets=No assigned fix version found" >> "$GITHUB_OUTPUT"
          else
            echo "Found Jira tickets:"
            echo "$TICKETS"
            echo "tickets<<EOF" >> "$GITHUB_OUTPUT"
            echo "$TICKETS" >> "$GITHUB_OUTPUT"
            echo "EOF" >> "$GITHUB_OUTPUT"
          fi

      - name: Determine status and failed stage
        id: status
        env:
          VALIDATE_RESULT: ${{ needs.validate-production.result }}
          PUBLISH_RESULT: ${{ needs.publish-to-npm.result }}
          RELEASE_RESULT: ${{ needs.create-github-release.result }}
        run: |
          set -euo pipefail
          if [[ "$VALIDATE_RESULT" == "success" \
             && "$PUBLISH_RESULT"  == "success" \
             && "$RELEASE_RESULT"  == "success" ]]; then
            echo "success=true" >> "$GITHUB_OUTPUT"
            echo "failed_stage=" >> "$GITHUB_OUTPUT"
            exit 0
          fi
          echo "success=false" >> "$GITHUB_OUTPUT"
          if [[ "$VALIDATE_RESULT" != "success" ]]; then
            echo "failed_stage=validate-production" >> "$GITHUB_OUTPUT"
          elif [[ "$PUBLISH_RESULT" != "success" ]]; then
            echo "failed_stage=publish-to-npm" >> "$GITHUB_OUTPUT"
          else
            echo "failed_stage=create-github-release" >> "$GITHUB_OUTPUT"
          fi

      - name: Send Slack success notification
        if: steps.status.outputs.success == 'true'
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "<!here>\n:react::react::react::react::react::react::react::react::react::react::react::react:\n\n*React Native:*\nnpm install react-native-appsflyer@${{ needs.validate-production.outputs.version }} is published to Production.\n\n:white_check_mark: rc-smoke/npm passed before promotion (verified by promote-release.yml).\n\n*Sources:*\n:github: https://github.com/${{ github.repository }}/tree/master\n:github: Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n:npm: https://www.npmjs.com/package/react-native-appsflyer/v/${{ needs.validate-production.outputs.version }}\n\n*Changes and fixes:*\n${{ steps.extract-info.outputs.changelog }}\n\n*Linked tickets and issues:*\n${{ steps.jira-tickets.outputs.tickets }}\n\n*Native SDKs:*\n:android: ${{ steps.extract-info.outputs.android_sdk }}\n:apple: ${{ steps.extract-info.outputs.ios_sdk }}\n\n:react::react::react::react::react::react::react::react::react::react::react::react:"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.CI_SLACK_HOOK }}

      - name: Send Slack failure notification
        if: steps.status.outputs.success == 'false'
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "<!here>\n:warning: *React Native production release failed at `${{ steps.status.outputs.failed_stage }}`*\n\nVersion: ${{ needs.validate-production.outputs.version }}\nRun: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\n*Stage results:*\n- validate-production: ${{ needs.validate-production.result }}\n- publish-to-npm: ${{ needs.publish-to-npm.result }}\n- create-github-release: ${{ needs.create-github-release.result }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.CI_SLACK_HOOK }}

  # ===========================================================================
  # RC Summary
  # ===========================================================================

  rc-summary:
    name: RC Summary
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-rc, run-ci, prepare-branch, run-e2e-ios, run-e2e-android, pre-publish-gate, validate-jira, publish-to-npm, create-prerelease]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'rc'

    steps:
      - name: Display RC Summary
        run: |
          echo "========================================="
          echo "RC Release Summary"
          echo "========================================="
          echo "Version: ${{ needs.validate-rc.outputs.version }}"
          echo "Dry Run: ${{ needs.validate-rc.outputs.is_dry_run }}"
          echo "-----------------------------------------"
          echo "RC-PREP validate:     ${{ needs.validate-rc.result }}"
          echo "Lint, Test & Build:   ${{ needs.run-ci.result }}"
          echo "RC-PREP branch:       ${{ needs.prepare-branch.result }}"
          echo "RC-E2E iOS:           ${{ needs.run-e2e-ios.result }}"
          echo "RC-E2E Android:       ${{ needs.run-e2e-android.result }}"
          echo "Pre-publish gate:     ${{ needs.pre-publish-gate.result }}"
          echo "Validate Jira:        ${{ needs.validate-jira.result }}"
          echo "Publish to npm:       ${{ needs.publish-to-npm.result }}"
          echo "Pre-release tag + PR: ${{ needs.create-prerelease.result }}"
          echo "========================================="

          ok() { [[ "$1" == "success" || "$1" == "skipped" ]]; }

          FAIL=0
          # validate-rc and pre-publish-gate must succeed (never legitimately skipped)
          [[ "${{ needs.validate-rc.result }}" == "success" ]] || FAIL=1
          [[ "${{ needs.pre-publish-gate.result }}" == "success" ]] || FAIL=1
          # downstream jobs may be skipped (dry-run, skip_e2e, etc.)
          ok "${{ needs.run-ci.result }}" || FAIL=1
          ok "${{ needs.prepare-branch.result }}" || FAIL=1
          ok "${{ needs.validate-jira.result }}" || FAIL=1
          ok "${{ needs.publish-to-npm.result }}" || FAIL=1
          ok "${{ needs.create-prerelease.result }}" || FAIL=1

          if [[ "$FAIL" == "0" ]]; then
            echo "RC Release Process Completed Successfully"
          else
            echo "RC Release Process Failed"
            echo "Check the logs above for details"
            exit 1
          fi

  # ===========================================================================
  # Production Release Summary
  # ===========================================================================

  release-summary:
    name: Release Summary
    runs-on: ubuntu-latest
    needs: [determine-release-type, validate-production, publish-to-npm, create-github-release]
    if: >-
      !cancelled() &&
      needs.determine-release-type.outputs.release_type == 'production'

    steps:
      - name: Display Release Summary
        env:
          VERSION: ${{ needs.validate-production.outputs.version }}
          DRY_RUN: ${{ needs.validate-production.outputs.is_dry_run }}
          VALIDATE_RESULT: ${{ needs.validate-production.result }}
          PUBLISH_RESULT: ${{ needs.publish-to-npm.result }}
          RELEASE_RESULT: ${{ needs.create-github-release.result }}
          REPO: ${{ github.repository }}
        run: |
          echo "========================================="
          echo "Production Release Summary"
          echo "========================================="
          echo "Version: $VERSION"
          echo "Dry Run: $DRY_RUN"
          echo "-----------------------------------------"
          echo "Validation: $VALIDATE_RESULT"
          echo "npm Publish: $PUBLISH_RESULT"
          echo "GitHub Release: $RELEASE_RESULT"
          echo "========================================="

          if [[ "$DRY_RUN" == "true" ]]; then
            echo "This was a DRY RUN - no actual publishing occurred"
            exit 0
          fi

          if [[ "$VALIDATE_RESULT" == "success" ]] && \
             [[ "$PUBLISH_RESULT" == "success" ]] && \
             [[ "$RELEASE_RESULT" == "success" ]]; then
            echo ""
            echo "Production Release Completed Successfully!"
            echo ""
            echo "Version $VERSION is now live!"
            echo ""
            echo "npm: https://www.npmjs.com/package/react-native-appsflyer/v/$VERSION"
            echo "GitHub: https://github.com/$REPO/releases/tag/v$VERSION"
          else
            echo ""
            echo "Production Release Failed"
            echo "Check the logs above for details and retry if necessary"
            exit 1
          fi
