---
# Reusable E2E workflow — single source of truth for the desktop E2E recipe.
#
# Callers:
#   - `.github/workflows/e2e.yml`     — PR/push, Linux-only smoke (blocking).
#   - `.github/workflows/release-staging.yml`    — pretest gate, all 3 OS, full suite.
#   - `.github/workflows/release-production.yml` — pretest gate, all 3 OS, full suite.
#
# Recipe per OS (identical across platforms — see e2e-run-session.sh):
#   1. Build the CEF app via `pnpm --filter openhuman-app test:e2e:build`.
#   2. Install Appium 3.x + the `chromium` driver.
#   3. Run `app/scripts/e2e-run-session.sh` which:
#        - launches the built binary,
#        - waits for CDP on :19222,
#        - prunes the prewarm `about:blank` target,
#        - downloads a chromedriver matching CEF's Chromium version,
#        - starts Appium and runs WDIO against `wdio.conf.ts`.
#
# Linux runs inside the project CI container under Xvfb (no native display).
# macOS / Windows run on GitHub-hosted runners.
#
# Caching: pnpm store, Swatinem rust-cache, and CEF runtime download
# (~400MB) are cached on every job. The CEF cache key matches what
# build-desktop.yml uses so cross-workflow hits are possible.
name: E2E (reusable)

on:
  workflow_call:
    inputs:
      ref:
        description:
          Git ref (tag or SHA) to test. Release workflows pass the
          freshly-pushed staging/production tag here so pretest validates
          the exact commit the build matrix will check out, not main HEAD
          at workflow_dispatch time. Defaults to empty (checkout uses its
          own default, i.e. the workflow's triggering ref).
        type: string
        default: ""
      run_linux:
        description: Run the Linux (Xvfb / container) E2E job.
        type: boolean
        default: true
      run_macos:
        description: Run the macOS E2E job.
        type: boolean
        default: false
      run_windows:
        description: Run the Windows E2E job.
        type: boolean
        default: false
      full:
        description:
          When true, run the entire spec suite via `e2e-run-session.sh` (no
          spec arg). When false, run the smoke spec + mega-flow (mega-flow
          non-blocking). Releases set this to true; PR runs leave it false.
        type: boolean
        default: false

permissions:
  contents: read

jobs:
  e2e-linux:
    if: inputs.run_linux
    name: E2E (Linux / Appium Chromium)
    runs-on: ubuntu-22.04
    container:
      image: ghcr.io/tinyhumansai/openhuman_ci:latest
    timeout-minutes: 90
    steps:
      - name: Checkout code
        uses: actions/checkout@v5
        with:
          ref: ${{ inputs.ref }}
          fetch-depth: 1
          submodules: recursive

      - name: Cache pnpm store
        uses: actions/cache@v5
        with:
          path: ~/.local/share/pnpm/store
          key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
          restore-keys: |
            pnpm-store-${{ runner.os }}-

      - name: Cache Rust build artifacts
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: |
            . -> target
            app/src-tauri -> target
          cache-on-failure: true
          key: e2e-linux-unified

      # CEF runtime download cache — matches the key shape used by
      # build-desktop.yml so a release build and an E2E run on the same
      # commit can share a single download.
      - name: Cache CEF binary distribution
        uses: actions/cache@v5
        with:
          path: |
            ~/.cache/tauri-cef
          key: cef-x86_64-unknown-linux-gnu-${{ hashFiles('app/src-tauri/Cargo.toml') }}
          restore-keys: |
            cef-x86_64-unknown-linux-gnu-

      - name: Cache Appium global install
        uses: actions/cache@v5
        with:
          path: |
            ~/.appium
            /usr/local/lib/node_modules/appium
          key: appium3-chromium-${{ runner.os }}-v1

      - name: Install JS dependencies
        run: pnpm install --frozen-lockfile

      - name: Ensure .env exists for E2E build
        run: |
          touch .env
          touch app/.env

      - name: Install Appium and chromium driver
        run: |
          if ! command -v appium >/dev/null 2>&1; then
            npm install -g appium@3
          fi
          # `appium driver list --installed` can miss cached installs on some
          # Appium builds; install idempotently and ignore "already installed".
          appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true

      - name: Build E2E app
        run: pnpm --filter openhuman-app test:e2e:build

      - name: Run E2E (smoke)
        if: ${{ !inputs.full }}
        run: |
          xvfb-run -a --server-args="-screen 0 1280x960x24" \
            bash app/scripts/e2e-run-session.sh test/e2e/specs/smoke.spec.ts smoke

      # Mega-flow exercises the OAuth-success-deep-link and Composio
      # trigger-lifecycle paths. Hard-fails on regressions — if the
      # deep-link → custom-event propagation race resurfaces, fix it
      # at the source rather than re-adding `continue-on-error`.
      - name: Run E2E (mega-flow)
        if: ${{ !inputs.full }}
        run: |
          xvfb-run -a --server-args="-screen 0 1280x960x24" \
            bash app/scripts/e2e-run-session.sh test/e2e/specs/mega-flow.spec.ts mega-flow

      - name: Run E2E (full suite)
        if: ${{ inputs.full }}
        env:
          E2E_BAIL_ON_FAILURE: ${{ vars.E2E_BAIL_ON_FAILURE || '' }}
        run: |
          BAIL_FLAG=""
          if [[ "${E2E_BAIL_ON_FAILURE:-}" == "1" ]]; then
            BAIL_FLAG="--bail"
          fi
          xvfb-run -a --server-args="-screen 0 1280x960x24" \
            bash app/scripts/e2e-run-all-flows.sh --skip-preflight $BAIL_FLAG

      - name: Upload E2E failure artifacts
        if: failure()
        uses: actions/upload-artifact@v5
        with:
          name: e2e-failure-logs-${{ runner.os }}-${{ github.run_id }}
          path: |
            /tmp/openhuman-e2e-app-*.log
            app/test/e2e/artifacts/
          retention-days: 7
          if-no-files-found: ignore

      - name: Write job summary
        if: always()
        run: |
          echo "## E2E Results (${{ runner.os }})" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          if [ -f /tmp/e2e-summary.txt ]; then
            cat /tmp/e2e-summary.txt >> $GITHUB_STEP_SUMMARY
          else
            echo "No summary file found." >> $GITHUB_STEP_SUMMARY
          fi

  # Rust-side E2E counterpart to the Tauri runs above. Same Linux-only
  # scope (CI does not run this on macOS or Windows — the Rust core is
  # platform-independent, so one OS is enough signal). Boots the same
  # `scripts/mock-api-server.mjs` the Tauri specs hit, then runs every
  # `tests/*_e2e.rs` suite against it.
  rust-e2e-linux:
    if: inputs.run_linux
    name: E2E (Linux / Rust integration suite)
    runs-on: ubuntu-22.04
    container:
      image: ghcr.io/tinyhumansai/openhuman_ci:latest
    timeout-minutes: 60
    env:
      CARGO_INCREMENTAL: '0'
      RUST_BACKTRACE: '1'
    steps:
      - name: Checkout code
        uses: actions/checkout@v5
        with:
          ref: ${{ inputs.ref }}
          fetch-depth: 1
          submodules: recursive

      - name: Cache pnpm store
        uses: actions/cache@v5
        with:
          path: ~/.local/share/pnpm/store
          key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
          restore-keys: |
            pnpm-store-${{ runner.os }}-

      - name: Cache Rust build artifacts
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: . -> target
          cache-on-failure: true
          key: rust-e2e-linux

      - name: Install JS dependencies
        run: pnpm install --frozen-lockfile

      - name: Ensure .env exists for tests
        run: |
          touch .env
          touch app/.env

      - name: Run Rust E2E suite (tests/*_e2e.rs vs mock backend)
        run: pnpm test:rust:e2e

      # No artifact uploads here either — same release-workflow reuse
      # concern as the Tauri job above. Mock-backend log lives at
      # /tmp/openhuman-rust-e2e-mock.log for local docker repro.

  e2e-macos:
    if: inputs.run_macos
    name: E2E (macOS / Appium Chromium)
    runs-on: macos-latest
    timeout-minutes: 90
    steps:
      - name: Checkout code
        uses: actions/checkout@v5
        with:
          ref: ${{ inputs.ref }}
          fetch-depth: 1
          submodules: recursive

      - name: Install pnpm
        uses: pnpm/action-setup@v4

      - name: Setup Node.js 24.x
        uses: actions/setup-node@v5
        with:
          node-version: 24.x
          cache: pnpm

      - name: Install Rust (rust-toolchain.toml)
        uses: dtolnay/rust-toolchain@1.93.0
        with:
          # macos-latest is arm64, but the vendored tauri-cli's build.rs
          # compiles a CEF helper for x86_64-apple-darwin (universal binary),
          # so the x86_64 libstd must be installed too.
          targets: x86_64-apple-darwin

      - name: Verify cargo resolves to real toolchain
        run: |
          rustup default 1.93.0 || true
          which cargo
          cargo --version

      - name: Cache Rust build artifacts
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: |
            . -> target
            app/src-tauri -> target
          cache-on-failure: true
          key: e2e-macos-unified-v2

      - name: Cache CEF binary distribution
        uses: actions/cache@v5
        with:
          path: |
            ~/Library/Caches/tauri-cef
          key: cef-aarch64-apple-darwin-${{ hashFiles('app/src-tauri/Cargo.toml') }}
          restore-keys: |
            cef-aarch64-apple-darwin-

      - name: Cache Appium global install
        uses: actions/cache@v5
        with:
          path: |
            ~/.appium
          key: appium3-chromium-${{ runner.os }}-v1

      - name: Install JS dependencies
        run: pnpm install --frozen-lockfile

      - name: Ensure .env exists for E2E build
        run: |
          touch .env
          touch app/.env

      - name: Install Appium and chromium driver
        run: |
          if ! command -v appium >/dev/null 2>&1; then
            npm install -g appium@3
          fi
          # `appium driver list --installed` can miss cached installs on some
          # Appium builds; install idempotently and ignore "already installed".
          appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true

      - name: Build E2E app
        run: pnpm --filter openhuman-app test:e2e:build

      # macOS rejects dynamic-framework loads from unsigned bundles — adhoc
      # signing satisfies the loader without a real developer-ID cert.
      - name: Adhoc-sign the .app bundle
        run: |
          codesign --force --deep --sign - \
            app/src-tauri/target/debug/bundle/macos/OpenHuman.app
          codesign --verify --deep --verbose=2 \
            app/src-tauri/target/debug/bundle/macos/OpenHuman.app

      - name: Run E2E (smoke + mega-flow)
        if: ${{ !inputs.full }}
        run: |
          bash app/scripts/e2e-run-session.sh test/e2e/specs/smoke.spec.ts smoke
          bash app/scripts/e2e-run-session.sh test/e2e/specs/mega-flow.spec.ts mega-flow

      - name: Run E2E (full suite)
        if: ${{ inputs.full }}
        run: bash app/scripts/e2e-run-session.sh

      # Artifact uploads intentionally omitted — see e2e-linux for the
      # reusable-workflow-is-also-used-by-releases rationale.

  e2e-windows:
    if: inputs.run_windows
    name: E2E (Windows / Appium Chromium)
    runs-on: windows-latest
    timeout-minutes: 90
    steps:
      - name: Checkout code
        uses: actions/checkout@v5
        with:
          ref: ${{ inputs.ref }}
          fetch-depth: 1
          submodules: recursive

      - name: Install pnpm
        uses: pnpm/action-setup@v4

      - name: Setup Node.js 24.x
        uses: actions/setup-node@v5
        with:
          node-version: 24.x
          cache: pnpm

      - name: Install Rust (rust-toolchain.toml)
        uses: dtolnay/rust-toolchain@1.93.0

      - name: Cache Rust build artifacts
        uses: Swatinem/rust-cache@v2
        with:
          workspaces: |
            . -> target
            app/src-tauri -> target
          cache-on-failure: true
          key: e2e-windows-unified

      - name: Cache CEF binary distribution
        uses: actions/cache@v5
        with:
          path: |
            ~/AppData/Local/tauri-cef
          key: cef-x86_64-pc-windows-msvc-${{ hashFiles('app/src-tauri/Cargo.toml') }}
          restore-keys: |
            cef-x86_64-pc-windows-msvc-

      - name: Cache Appium global install
        uses: actions/cache@v5
        with:
          path: |
            ~/.appium
          key: appium3-chromium-${{ runner.os }}-v1

      - name: Install JS dependencies
        run: pnpm install --frozen-lockfile

      - name: Ensure .env exists for E2E build
        shell: bash
        run: |
          touch .env
          touch app/.env

      - name: Install Appium and chromium driver
        shell: bash
        run: |
          if ! command -v appium >/dev/null 2>&1; then
            npm install -g appium@3
          fi
          # `appium driver list --installed` can miss cached installs on some
          # Appium builds; install idempotently and ignore "already installed".
          appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true

      - name: Build E2E app
        run: pnpm --filter openhuman-app test:e2e:build

      - name: Run E2E (smoke + mega-flow)
        if: ${{ !inputs.full }}
        shell: bash
        run: |
          bash app/scripts/e2e-run-session.sh test/e2e/specs/smoke.spec.ts smoke
          bash app/scripts/e2e-run-session.sh test/e2e/specs/mega-flow.spec.ts mega-flow

      - name: Run E2E (full suite)
        if: ${{ inputs.full }}
        shell: bash
        run: bash app/scripts/e2e-run-session.sh

      # Artifact uploads intentionally omitted — see e2e-linux for the
      # reusable-workflow-is-also-used-by-releases rationale.
