name: Regenerate

on:
  repository_dispatch:
    types: [openapi-updated]
  workflow_dispatch:

jobs:
  generate:
    name: Regenerate from OpenAPI
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          fetch-depth: 0

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt

      - name: Setup Java (for openapi-generator)
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'

      - name: Install OpenAPI Generator
        run: npm install -g @openapitools/openapi-generator-cli

      - name: Fetch latest OpenAPI spec
        run: |
          curl -f -o openapi.yaml https://zernio.com/openapi.yaml
          echo "Fetched OpenAPI spec"

      - name: Generate SDK
        run: |
          openapi-generator-cli generate \
            -i openapi.yaml \
            -g rust \
            -o . \
            --skip-validate-spec \
            --additional-properties=packageName=late,library=reqwest \
            --git-user-id=zernio-dev \
            --git-repo-id=zernio-rust

      - name: Patch README install instructions
        run: |
          python3 -c "
          import re
          with open('README.md', 'r') as f:
              content = f.read()
          install_section = '''## Installation

          Add the crate to your project:

          \`\`\`bash
          cargo add late
          \`\`\`

          Or add it manually to your \`Cargo.toml\`:

          \`\`\`toml
          [dependencies]
          late = \"*\"
          \`\`\`'''
          import textwrap
          install_section = textwrap.dedent(install_section)
          content = re.sub(r'## Installation.*?(?=\n## )', install_section + '\n\n', content, flags=re.DOTALL)
          with open('README.md', 'w') as f:
              f.write(content)
          "

      # Switch from native-tls to rustls-tls to avoid native-tls upstream bugs
      # (e.g. v0.2.17 missing Protocol::Tlsv13 match arm) and remove system
      # OpenSSL dependency. Pure Rust TLS is more portable for CI builds.
      - name: Use rustls-tls instead of native-tls
        run: |
          sed -i 's/default = \["native-tls"\]/default = ["rustls-tls"]/' Cargo.toml

      - name: Format code
        run: cargo fmt || true

      - name: Build
        run: cargo build

      - name: Run tests
        run: cargo test

      - name: Check for changes
        id: changes
        run: |
          git add -A
          if git diff --staged --quiet; then
            echo "has_changes=false" >> $GITHUB_OUTPUT
          else
            echo "has_changes=true" >> $GITHUB_OUTPUT
          fi

      - name: Get next version
        if: steps.changes.outputs.has_changes == 'true'
        id: version
        run: |
          LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
          NEW_VERSION=$(echo $LATEST_TAG | awk -F. '{printf "v%d.%d.%d", $1, $2, $3+1}' | sed 's/vv/v/')
          CARGO_VERSION=$(echo $NEW_VERSION | sed 's/v//')
          echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
          echo "cargo_version=$CARGO_VERSION" >> $GITHUB_OUTPUT

      - name: Update Cargo.toml version
        if: steps.changes.outputs.has_changes == 'true'
        run: |
          sed -i "s/^version = .*/version = \"${{ steps.version.outputs.cargo_version }}\"/" Cargo.toml || true

      - name: Commit and push
        if: steps.changes.outputs.has_changes == 'true'
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add -A
          git commit -m "chore: regenerate from OpenAPI spec

          - Auto-generated SDK updates
          - Version: ${{ steps.version.outputs.new_version }}"
          git push

      - name: Build
        if: steps.changes.outputs.has_changes == 'true'
        run: cargo build --release

      - name: Publish as late to crates.io
        if: steps.changes.outputs.has_changes == 'true'
        run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }}
        continue-on-error: true

      - name: Publish as zernio to crates.io
        if: steps.changes.outputs.has_changes == 'true'
        run: |
          sed -i 's/^name = "late"/name = "zernio"/' Cargo.toml
          cargo publish --allow-dirty --token ${{ secrets.CRATES_IO_TOKEN }}
        continue-on-error: true

      - name: Restore Cargo.toml package name
        if: steps.changes.outputs.has_changes == 'true'
        run: |
          sed -i 's/^name = "zernio"/name = "late"/' Cargo.toml

      - name: Create GitHub Release
        if: steps.changes.outputs.has_changes == 'true'
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ steps.version.outputs.new_version }}
          name: ${{ steps.version.outputs.new_version }}
          generate_release_notes: true
          body: |
            ## Auto-generated SDK Update

            Available as both `late` and `zernio` on crates.io:
            ```toml
            [dependencies]
            late = "${{ steps.version.outputs.cargo_version }}"
            # or
            zernio = "${{ steps.version.outputs.cargo_version }}"
            ```
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
