# =============================================================================
# Docker Workflow — Build & Push to Gitea Container Registry
# =============================================================================
#
# PURPOSE:
#   Build Docker images generically; optionally push to the Gitea Container
#   Registry at git.hiddenden.cafe.
#
# TRIGGERS:
#   - pull_request       → build only (never push)
#   - push to main       → build; push only if ENABLE_DOCKER=true AND DOCKER_PUSH=true
#   - tag v*             → build; push only if DOCKER_PUSH=true AND DOCKER_PUSH_ON_TAG=true
#
# DETECTION:
#   - Dockerfile exists         → docker build
#   - docker-compose.yml exists → docker compose build
#   - Neither                   → exit 0 gracefully
#
# NAMING (Gitea convention):
#   Image ref: ${REGISTRY_HOST}/${IMAGE_OWNER}/${IMAGE_NAME}:${TAG}
#   Example:   git.hiddenden.cafe/myorg/myrepo:1.2.3
#
# AUTHENTICATION:
#   Uses PAT-based secrets (recommended for Gitea Actions):
#     - REGISTRY_USERNAME — your Gitea username or bot account
#     - REGISTRY_TOKEN    — a Personal Access Token with package:write scope
#   Set these in: Repository Settings → Secrets (or Organization Secrets).
#   NEVER echo secrets in logs.
#
# CONFIG:
#   All settings loaded from .ci/config.env. See docs/DOCKER.md.
#
# =============================================================================

name: Docker

on:
  push:
    branches:
      - main
    tags:
      - "v*"
  pull_request:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      # -----------------------------------------------------------------------
      # Step 1: Checkout
      # -----------------------------------------------------------------------
      - name: Checkout
        uses: actions/checkout@v4

      # -----------------------------------------------------------------------
      # Step 2: Load configuration
      # -----------------------------------------------------------------------
      - name: Load config
        run: |
          if [ -f .ci/config.env ]; then
            set -a
            source .ci/config.env
            set +a
            echo "Config loaded from .ci/config.env"
          else
            echo "WARNING: .ci/config.env not found, using defaults"
          fi

          # Export with defaults
          echo "ENABLE_DOCKER=${ENABLE_DOCKER:-true}"           >> "$GITHUB_ENV"
          echo "DOCKER_PUSH=${DOCKER_PUSH:-false}"              >> "$GITHUB_ENV"
          echo "DOCKER_PUSH_ON_BRANCH=${DOCKER_PUSH_ON_BRANCH:-true}" >> "$GITHUB_ENV"
          echo "DOCKER_PUSH_ON_TAG=${DOCKER_PUSH_ON_TAG:-true}" >> "$GITHUB_ENV"
          echo "REGISTRY_HOST=${REGISTRY_HOST:-git.hiddenden.cafe}" >> "$GITHUB_ENV"
          echo "IMAGE_OWNER_CFG=${IMAGE_OWNER:-auto}"           >> "$GITHUB_ENV"
          echo "IMAGE_NAME_CFG=${IMAGE_NAME:-auto}"             >> "$GITHUB_ENV"
          echo "DOCKER_TAG_STRATEGY=${DOCKER_TAG_STRATEGY:-semver+latest}" >> "$GITHUB_ENV"
          echo "DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}"         >> "$GITHUB_ENV"

      # -----------------------------------------------------------------------
      # Step 3: Check if Docker is enabled
      # -----------------------------------------------------------------------
      - name: Check if Docker is enabled
        run: |
          if [ "$ENABLE_DOCKER" != "true" ]; then
            echo "Docker is disabled (ENABLE_DOCKER=$ENABLE_DOCKER). Exiting."
            # We still exit 0 — graceful skip.
            echo "SKIP_DOCKER=true" >> "$GITHUB_ENV"
          fi

      # -----------------------------------------------------------------------
      # Step 4: Detect Dockerfile or docker-compose.yml
      # -----------------------------------------------------------------------
      - name: Detect Docker files
        if: env.SKIP_DOCKER != 'true'
        run: |
          if [ -f Dockerfile ]; then
            echo "DOCKER_MODE=dockerfile" >> "$GITHUB_ENV"
            echo "Detected: Dockerfile"
          elif [ -f docker-compose.yml ] || [ -f docker-compose.yaml ]; then
            echo "DOCKER_MODE=compose" >> "$GITHUB_ENV"
            echo "Detected: docker-compose.yml"
          else
            echo "No Dockerfile or docker-compose.yml found. Skipping."
            echo "SKIP_DOCKER=true" >> "$GITHUB_ENV"
          fi

      # -----------------------------------------------------------------------
      # Step 5: Derive image owner and name dynamically
      #
      # Logic:
      #   FULL_REPO is derived from (in priority order):
      #     1. $GITEA_REPOSITORY   (Gitea native env var)
      #     2. github.repository   (Gitea Actions compatibility fallback)
      #   Format: "owner/repo"
      #
      #   If IMAGE_OWNER=auto → use the owner part
      #   If IMAGE_NAME=auto  → use the repo part
      #   Otherwise, use the explicit config values.
      # -----------------------------------------------------------------------
      - name: Derive image naming
        if: env.SKIP_DOCKER != 'true'
        run: |
          # Determine FULL_REPO (owner/repo)
          # Gitea Actions sets GITEA_REPOSITORY natively in some versions.
          # It also maps github.repository for compatibility.
          FULL_REPO="${GITEA_REPOSITORY:-${{ github.repository }}}"

          if [ -z "$FULL_REPO" ]; then
            echo "ERROR: Could not determine repository (GITEA_REPOSITORY and github.repository are both empty)"
            exit 1
          fi

          # Split into OWNER and REPO
          OWNER="$(echo "$FULL_REPO" | cut -d'/' -f1)"
          REPO="$(echo "$FULL_REPO" | cut -d'/' -f2)"

          echo "Derived FULL_REPO=$FULL_REPO  OWNER=$OWNER  REPO=$REPO"

          # Apply config overrides
          if [ "$IMAGE_OWNER_CFG" = "auto" ]; then
            FINAL_OWNER="$OWNER"
          else
            FINAL_OWNER="$IMAGE_OWNER_CFG"
          fi

          if [ "$IMAGE_NAME_CFG" = "auto" ]; then
            FINAL_NAME="$REPO"
          else
            FINAL_NAME="$IMAGE_NAME_CFG"
          fi

          # Docker requires all image references to be lowercase
          FINAL_OWNER="$(echo "$FINAL_OWNER" | tr '[:upper:]' '[:lower:]')"
          FINAL_NAME="$(echo "$FINAL_NAME" | tr '[:upper:]' '[:lower:]')"

          # Construct the full image reference (without tag)
          IMAGE_REF="${REGISTRY_HOST}/${FINAL_OWNER}/${FINAL_NAME}"
          echo "Image reference: ${IMAGE_REF}:<tag>"

          echo "IMAGE_REF=${IMAGE_REF}" >> "$GITHUB_ENV"

      # -----------------------------------------------------------------------
      # Step 6: Determine tags based on trigger and strategy
      #
      # Tag rules:
      #   - PR:              build only, tag = "pr-<number>" (local only)
      #   - Push to branch:  tag = branch name (e.g., "main")
      #   - Tag v1.2.3:      tag = "1.2.3"; also "latest" if strategy includes it
      # -----------------------------------------------------------------------
      - name: Determine tags
        if: env.SKIP_DOCKER != 'true'
        run: |
          TAGS=""
          SHOULD_PUSH=false
          REF="${GITHUB_REF:-}"

          echo "Event: ${{ github.event_name }}"
          echo "Ref:   ${REF}"

          # --- Pull Request: build only ---
          if [ "${{ github.event_name }}" = "pull_request" ]; then
            TAGS="${IMAGE_REF}:pr-${{ github.event.number }}"
            SHOULD_PUSH=false
            echo "PR build — will NOT push"

          # --- Tag push (v*) ---
          elif echo "${REF}" | grep -qE '^refs/tags/v'; then
            # Extract version: refs/tags/v1.2.3 → 1.2.3
            VERSION="$(echo "${REF}" | sed 's|refs/tags/v||')"
            TAGS="${IMAGE_REF}:${VERSION}"

            # Optionally add :latest
            if echo "$DOCKER_TAG_STRATEGY" | grep -qi 'latest'; then
              TAGS="${TAGS},${IMAGE_REF}:latest"
            fi

            if [ "$DOCKER_PUSH" = "true" ] && [ "$DOCKER_PUSH_ON_TAG" = "true" ]; then
              SHOULD_PUSH=true
            fi
            echo "Tag push — version=${VERSION}, push=${SHOULD_PUSH}"

          # --- Branch push ---
          elif echo "${REF}" | grep -q '^refs/heads/'; then
            BRANCH="$(echo "${REF}" | sed 's|refs/heads/||')"
            TAGS="${IMAGE_REF}:${BRANCH}"

            if [ "$DOCKER_PUSH" = "true" ] && [ "$DOCKER_PUSH_ON_BRANCH" = "true" ]; then
              SHOULD_PUSH=true
            fi
            echo "Branch push — branch=${BRANCH}, push=${SHOULD_PUSH}"

          else
            echo "Unknown ref type: ${REF}. Building with tag 'dev'."
            TAGS="${IMAGE_REF}:dev"
            SHOULD_PUSH=false
          fi

          echo "DOCKER_TAGS=${TAGS}" >> "$GITHUB_ENV"
          echo "SHOULD_PUSH=${SHOULD_PUSH}" >> "$GITHUB_ENV"
          echo "Final tags: ${TAGS}"
          echo "Will push:  ${SHOULD_PUSH}"

      # -----------------------------------------------------------------------
      # Step 7: Build the Docker image
      # -----------------------------------------------------------------------
      - name: Build Docker image
        if: env.SKIP_DOCKER != 'true'
        run: |
          if [ "$DOCKER_MODE" = "dockerfile" ]; then
            # Build with the first tag; additional tags are added after
            PRIMARY_TAG="$(echo "$DOCKER_TAGS" | cut -d',' -f1)"
            echo ">>> docker build -t ${PRIMARY_TAG} ."
            docker build -t "${PRIMARY_TAG}" .

            # Tag additional images if present
            IFS=',' read -ra TAG_ARRAY <<< "$DOCKER_TAGS"
            for tag in "${TAG_ARRAY[@]:1}"; do
              echo ">>> docker tag ${PRIMARY_TAG} ${tag}"
              docker tag "${PRIMARY_TAG}" "${tag}"
            done

          elif [ "$DOCKER_MODE" = "compose" ]; then
            echo ">>> docker compose build"
            docker compose build
          fi

      # -----------------------------------------------------------------------
      # Step 8: Login to registry (only when pushing)
      #
      # Uses PAT-based auth. Requires secrets:
      #   REGISTRY_USERNAME — Gitea username or bot
      #   REGISTRY_TOKEN    — PAT with package:write scope
      # -----------------------------------------------------------------------
      - name: Login to container registry
        if: env.SKIP_DOCKER != 'true' && env.SHOULD_PUSH == 'true'
        run: |
          echo "Logging in to ${REGISTRY_HOST}..."
          # Use --password-stdin to avoid leaking the token in process list
          echo "${{ secrets.REGISTRY_TOKEN }}" | \
            docker login "${REGISTRY_HOST}" \
              -u "${{ secrets.REGISTRY_USERNAME }}" \
              --password-stdin

      # -----------------------------------------------------------------------
      # Step 9: Push Docker image(s)
      # -----------------------------------------------------------------------
      - name: Push Docker image
        if: env.SKIP_DOCKER != 'true' && env.SHOULD_PUSH == 'true'
        run: |
          IFS=',' read -ra TAG_ARRAY <<< "$DOCKER_TAGS"
          for tag in "${TAG_ARRAY[@]}"; do
            echo ">>> docker push ${tag}"
            docker push "${tag}"
          done

      # -----------------------------------------------------------------------
      # Step 10: Summary
      # -----------------------------------------------------------------------
      - name: Docker Summary
        if: always()
        run: |
          echo "=============================="
          echo " Docker Workflow Complete"
          echo " Mode:     ${DOCKER_MODE:-skipped}"
          echo " Tags:     ${DOCKER_TAGS:-none}"
          echo " Pushed:   ${SHOULD_PUSH:-false}"
          echo "=============================="
