name: Release

on:
    push:
        tags:
            - "v*"

env:
    UV_VERSION: "0.8.0"
    PYTHON_VERSION: "3.13"
    NOX_DEFAULT_VENV_BACKEND: "uv"

jobs:
    build-wheel:
        runs-on: docker
        container:
            image: python:3.13-slim
        steps:
            - name: Install Node.js (required by actions/checkout)
              run: |
                  apt-get update && apt-get install -y -qq nodejs && rm -rf /var/lib/apt/lists/*

            - uses: actions/checkout@v4

            - name: Install uv and nox
              run: |
                  pip install -q uv==${{ env.UV_VERSION }} nox

            - name: Build wheel via nox
              run: |
                  nox -s build
              env:
                  NOX_DEFAULT_VENV_BACKEND: uv

            - name: Upload wheel artifact
              uses: actions/upload-artifact@v3
              with:
                  name: wheel
                  path: dist/*.whl
                  retention-days: 30

    build-docker:
        runs-on: docker
        container:
            image: docker:dind
            options: --privileged
        needs: [build-wheel]
        steps:
            - name: Start Docker daemon and install dependencies
              run: |
                  dockerd &
                  apk add --no-cache git nodejs
                  for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break || sleep 1; done

            - uses: actions/checkout@v4

            - name: Extract tag name
              id: tag
              run: |
                  TAG_NAME="${FORGEJO_REF_NAME:-${GITHUB_REF_NAME:-unknown}}"
                  echo "TAG_NAME=${TAG_NAME}" >> $FORGEJO_OUTPUT

            - name: Build Docker image
              run: |
                  TAG="${{ steps.tag.outputs.TAG_NAME }}"
                  docker build \
                    -t "${{ secrets.CONTAINER_REGISTRY }}:${TAG}" \
                    -t "${{ secrets.CONTAINER_REGISTRY }}:latest" \
                    .

            - name: Push Docker image to registry
              if: secrets.CONTAINER_REGISTRY != ''
              run: |
                  TAG="${{ steps.tag.outputs.TAG_NAME }}"
                  if [ -n "${{ secrets.CONTAINER_REGISTRY_USER }}" ]; then
                    echo "${{ secrets.CONTAINER_REGISTRY_PASSWORD }}" | \
                      docker login \
                        -u "${{ secrets.CONTAINER_REGISTRY_USER }}" \
                        --password-stdin \
                        "${{ secrets.CONTAINER_REGISTRY }}"
                  fi
                  docker push "${{ secrets.CONTAINER_REGISTRY }}:${TAG}"
                  docker push "${{ secrets.CONTAINER_REGISTRY }}:latest"

    create-release:
        runs-on: docker
        container:
            image: python:3.13-slim
        needs: [build-wheel, build-docker]
        steps:
            - name: Install system dependencies
              run: |
                  apt-get update && apt-get install -y -qq nodejs curl jq git && rm -rf /var/lib/apt/lists/*

            - uses: actions/checkout@v4
              with:
                  # Fetch full history so we can push tags and commits back
                  fetch-depth: 0
                  # Use FORGEJO_TOKEN so the checkout token has write scope.
                  # The default GITHUB_TOKEN / FORGEJO_TOKEN provided by the
                  # runner is read-only for push operations in many Forgejo
                  # configurations; supplying an explicit token with write
                  # permissions resolves the "unable to push" failure.
                  token: ${{ secrets.FORGEJO_TOKEN }}

            - name: Configure git identity for push operations
              # Required so that any git commit or tag created by this job
              # has a valid author. Without this, `git push` may succeed but
              # `git commit` (e.g., for changelog auto-commits) will fail.
              env:
                  FORGEJO_URL: ${{ secrets.FORGEJO_URL }}
                  FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
              run: |
                  git config user.name "CleverAgents CI"
                  git config user.email "ci@cleverthis.com"
                  # Configure HTTPS credential helper so that git push uses
                  # the FORGEJO_TOKEN secret rather than the default (often
                  # read-only) runner token.  This is the canonical fix for
                  # "unable to push to repository" in Forgejo Actions.
                  FORGEJO_HOST=$(echo "${FORGEJO_URL}" | sed 's|https\?://||' | cut -d/ -f1)
                  git config credential.helper store
                  echo "https://ci:${FORGEJO_TOKEN}@${FORGEJO_HOST}" > ~/.git-credentials
                  chmod 600 ~/.git-credentials

            - name: Smoke-test push access
              # Validates that the CI runner can push to the repository before
              # attempting the real push steps.  A failure here means the
              # FORGEJO_TOKEN secret is missing, expired, or lacks write scope.
              env:
                  FORGEJO_URL: ${{ secrets.FORGEJO_URL }}
                  FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
              run: |
                  REPO="${{ forgejo.repository }}"
                  API_URL="${FORGEJO_URL}/api/v1/repos/${REPO}"
                  HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
                    -H "Authorization: token ${FORGEJO_TOKEN}" \
                    "${API_URL}")
                  if [ "${HTTP_STATUS}" != "200" ]; then
                    echo "ERROR: FORGEJO_TOKEN cannot access repository API (HTTP ${HTTP_STATUS})."
                    echo "Ensure the FORGEJO_TOKEN secret is set in Repository Settings > Actions > Secrets"
                    echo "and that the token has 'repository' (write) scope."
                    exit 1
                  fi
                  # Verify push permission by checking the token's permissions
                  PUSH_ALLOWED=$(curl -s \
                    -H "Authorization: token ${FORGEJO_TOKEN}" \
                    "${API_URL}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(str(d.get('permissions',{}).get('push',False)).lower())")
                  if [ "${PUSH_ALLOWED}" != "true" ]; then
                    echo "ERROR: FORGEJO_TOKEN does not have push (write) permission on this repository."
                    echo "Grant the token 'Contents: Write' permission or use a token with full repository scope."
                    exit 1
                  fi
                  echo "Push access verified: FORGEJO_TOKEN has write permission on ${REPO}"

            - name: Download wheel artifact
              uses: actions/download-artifact@v3
              with:
                  name: wheel
                  path: dist/

            - name: Extract tag name
              id: tag
              run: |
                  TAG_NAME="${FORGEJO_REF_NAME:-${GITHUB_REF_NAME:-unknown}}"
                  echo "TAG_NAME=${TAG_NAME}" >> $FORGEJO_OUTPUT

            - name: Create Forgejo release with wheel
              env:
                  FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
                  FORGEJO_URL: ${{ secrets.FORGEJO_URL }}
              run: |
                  TAG="${{ steps.tag.outputs.TAG_NAME }}"
                  REPO="${{ forgejo.repository }}"
                  API_URL="${FORGEJO_URL}/api/v1/repos/${REPO}/releases"

                  # Create the release
                  RELEASE_ID=$(curl -s -X POST "${API_URL}" \
                    -H "Authorization: token ${FORGEJO_TOKEN}" \
                    -H "Content-Type: application/json" \
                    -d "{
                      \"tag_name\": \"${TAG}\",
                      \"name\": \"${TAG}\",
                      \"body\": \"Release ${TAG}\",
                      \"draft\": false,
                      \"prerelease\": false
                    }" | jq -r '.id')

                  echo "Created release ID: ${RELEASE_ID}"

                  # Attach wheel artifacts
                  for whl in dist/*.whl; do
                    FILENAME=$(basename "${whl}")
                    curl -s -X POST \
                      "${API_URL}/${RELEASE_ID}/assets?name=${FILENAME}" \
                      -H "Authorization: token ${FORGEJO_TOKEN}" \
                      -H "Content-Type: application/octet-stream" \
                      --data-binary "@${whl}"
                    echo "Attached ${FILENAME} to release"
                  done
