name: Agent CI/CD

on:
  push:
    tags:
      - "v*"
      - "latest"
  workflow_dispatch: {}

jobs:
  docker-image:
    runs-on: ubuntu-22.04
    if: startsWith(github.ref, 'refs/tags/')
    permissions:
      contents: read
    defaults:
      run:
        shell: bash

    steps:
      - name: Setup tools
        run: |
          sudo apt-get update -qq && sudo apt-get install -y -qq jq
          jq --version

      - name: Checkout code
        env:
          SERVER_URL: ${{ github.server_url }}
          REPOSITORY: ${{ github.repository }}
          COMMIT_SHA: ${{ github.sha }}
          GIT_USERNAME: ${{ github.actor }}
          GIT_TOKEN: ${{ github.token }}
        run: |
          case "$SERVER_URL" in
            http://*)
              AUTH_SERVER_URL="http://${GIT_USERNAME}:${GIT_TOKEN}@${SERVER_URL#http://}"
              ;;
            https://*)
              AUTH_SERVER_URL="https://${GIT_USERNAME}:${GIT_TOKEN}@${SERVER_URL#https://}"
              ;;
            *)
              AUTH_SERVER_URL="$SERVER_URL"
              ;;
          esac

          if [ ! -d .git ]; then
            git init .
          fi

          if git remote get-url origin >/dev/null 2>&1; then
            git remote set-url origin "${AUTH_SERVER_URL}/${REPOSITORY}.git"
          else
            git remote add origin "${AUTH_SERVER_URL}/${REPOSITORY}.git"
          fi

          git fetch --depth=1 origin "$COMMIT_SHA"
          git checkout --force --detach FETCH_HEAD
          git clean -ffdx

      - name: Normalize image metadata
        env:
          RAW_REGISTRY_HOST: ${{ vars.REGISTRY_HOST }}
          RAW_REPOSITORY: ${{ github.repository }}
          RAW_REF: ${{ github.ref }}
          RAW_REF_NAME: ${{ github.ref_name }}
        run: |
          RAW_REGISTRY_HOST="$(printf '%s' "${RAW_REGISTRY_HOST}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"

          if [ -z "${RAW_REGISTRY_HOST}" ]; then
            echo "Missing required repository variable: REGISTRY_HOST"
            exit 1
          fi

          REGISTRY_HOST="${RAW_REGISTRY_HOST#http://}"
          REGISTRY_HOST="${REGISTRY_HOST#https://}"
          REGISTRY_HOST="${REGISTRY_HOST%/}"

          if [ -z "${REGISTRY_HOST}" ]; then
            echo "Repository variable REGISTRY_HOST resolves to an empty host"
            exit 1
          fi

          REPOSITORY_PATH="${RAW_REPOSITORY#/}"
          IMAGE_REPOSITORY_PATH="$(printf '%s' "$REPOSITORY_PATH" | tr '[:upper:]' '[:lower:]')"
          IMAGE_NAME="${REGISTRY_HOST}/${IMAGE_REPOSITORY_PATH}"
          IMAGE_TAG="${RAW_REF_NAME}"
          {
            echo "REGISTRY_HOST=${REGISTRY_HOST}"
            echo "REPOSITORY_PATH=${REPOSITORY_PATH}"
            echo "IMAGE_REPOSITORY_PATH=${IMAGE_REPOSITORY_PATH}"
            echo "IMAGE_NAME=${IMAGE_NAME}"
            echo "IMAGE_TAG=${IMAGE_TAG}"
            echo "IMAGE_REF=${IMAGE_NAME}:${IMAGE_TAG}"
          } >> "$GITHUB_ENV"

      - name: Login to Gitea Container Registry
        env:
          REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
          REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
        run: |
          if [ -z "${REGISTRY_HOST:-}" ]; then
            echo "Missing resolved environment value: REGISTRY_HOST"
            echo "The previous step should write REGISTRY_HOST into GITHUB_ENV."
            exit 1
          fi

          if [ -z "${REGISTRY_USERNAME}" ]; then
            echo "Missing required repository secret: REGISTRY_USERNAME"
            exit 1
          fi

          if [ -z "${REGISTRY_PASSWORD}" ]; then
            echo "Missing required repository secret: REGISTRY_PASSWORD"
            exit 1
          fi

          echo "Logging into registry host: ${REGISTRY_HOST}"
          echo "${REGISTRY_PASSWORD}" | docker login "$REGISTRY_HOST" \
            --username "${REGISTRY_USERNAME}" \
            --password-stdin

      - name: Build and Push Image
        run: |
          if [ -z "${IMAGE_NAME:-}" ] || [ -z "${IMAGE_TAG:-}" ]; then
            echo "Missing resolved image metadata: IMAGE_NAME or IMAGE_TAG"
            exit 1
          fi

          push_with_retry() {
            image_ref="$1"
            attempt=1
            max_attempts=3

            while [ "$attempt" -le "$max_attempts" ]; do
              if docker push "$image_ref"; then
                return 0
              fi

              if [ "$attempt" -eq "$max_attempts" ]; then
                return 1
              fi

              echo "Push failed for $image_ref (attempt $attempt/$max_attempts); retrying in 10s..."
              attempt=$((attempt + 1))
              sleep 10
            done
          }

          if [ "${IMAGE_TAG}" = "latest" ]; then
            docker build \
              --network=host \
              -f ./Dockerfile \
              -t "${IMAGE_NAME}:latest" \
              .
            push_with_retry "${IMAGE_NAME}:latest"
          else
            docker build \
              --network=host \
              -f ./Dockerfile \
              -t "${IMAGE_NAME}:${IMAGE_TAG}" \
              -t "${IMAGE_NAME}:latest" \
              .
            push_with_retry "${IMAGE_NAME}:${IMAGE_TAG}"
            push_with_retry "${IMAGE_NAME}:latest"
          fi

      - name: Notify Deploy Server
        run: |
          post_deploy_webhook() {
            label="$1"
            payload="$2"
            webhook_url="${{ vars.DEPLOY_WEBHOOK_URL }}"
            token="${{ secrets.DEPLOY_WEBHOOK_TOKEN }}"

            # Trim whitespace
            webhook_url=$(echo "$webhook_url" | xargs)

            echo "[$label] Calling webhook: $webhook_url"

            http_code=$(curl -sS -D /tmp/deploy_headers.txt -o /tmp/deploy_response.txt -w "%{http_code}" -X POST "$webhook_url" \
              -H "Content-Type: application/json" \
              -H "Authorization: Bearer $token" \
              -d "$payload")

            echo "[$label] webhook HTTP status: ${http_code}"
            if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
              return 0
            fi

            echo "[$label] response headers:"
            cat /tmp/deploy_headers.txt
            echo "[$label] response body:"
            cat /tmp/deploy_response.txt
            return 1
          }

          PRIMARY_PAYLOAD="{\"image\":\"${IMAGE_REF}\",\"tag\":\"${IMAGE_TAG}\",\"repo\":\"${REPOSITORY_PATH}\"}"
          FALLBACK_PAYLOAD="{\"image\":\"${IMAGE_REF}\",\"tag\":\"${IMAGE_TAG}\",\"repo\":\"${IMAGE_REPOSITORY_PATH}\"}"

          echo "Deploy webhook target: ${{ vars.DEPLOY_WEBHOOK_URL }}"
          echo "Deploy payload(primary): image=${IMAGE_REF}, tag=${IMAGE_TAG}, repo=${REPOSITORY_PATH}"
          if post_deploy_webhook "primary" "$PRIMARY_PAYLOAD"; then
            exit 0
          fi

          echo "Primary webhook request failed, retrying with lowercase repo path..."
          echo "Deploy payload(fallback): image=${IMAGE_REF}, tag=${IMAGE_TAG}, repo=${IMAGE_REPOSITORY_PATH}"
          if post_deploy_webhook "fallback" "$FALLBACK_PAYLOAD"; then
            exit 0
          fi

          echo "Deploy webhook failed after primary and fallback attempts."
          exit 1

  deploy-fallback-log:
    runs-on: ubuntu-22.04
    needs: docker-image
    if: failure()
    steps:
      - name: Deployment not triggered
        run: echo "Image build/push failed, deployment webhook was not called."
