name: Build Service Images

on:
  workflow_call:
    inputs:
      push_images:
        description: "Push service images instead of local builds"
        type: boolean
        default: true

      dockerhub_namespace:
        description: "Docker Hub namespace (user/org)"
        type: string

      # Base image references (full image URL)
      node_builder_image:
        type: string
        default: "node:22-bookworm"

      node_runtime_image:
        type: string
        default: "node:22-slim"

      go_runtime_image:
        type: string
        default: "golang:1.25"

  workflow_dispatch:
    inputs:
      push_images:
        type: boolean
        default: true

      dockerhub_namespace:
        description: "Docker Hub namespace (user/org)"
        type: string
        default: "cloudneutral"

      node_builder_image:
        type: string
        default: "node:22-bookworm"

      node_runtime_image:
        type: string
        default: "node:22-slim"

      go_runtime_image:
        type: string
        default: "golang:1.25"

  push:
    branches: [ main ]
    paths:
      - "account/**"
      - "dashboard/**"
      - "rag-server/**"
      - "xcontrol-init/**"

permissions:
  contents: read
  packages: write
  id-token: write

env:
  REGISTRY: ghcr.io
  ORG: cloud-neutral-toolkit

  # Base image references (tag or digest)
  GO_RUNTIME_IMAGE: ${{ inputs.go_runtime_image || github.event.inputs.go_runtime_image || 'golang:1.25' }}
  NODE_BUILDER_IMAGE: ${{ inputs.node_builder_image || github.event.inputs.node_builder_image || 'node:22-bookworm' }}
  NODE_RUNTIME_IMAGE: ${{ inputs.node_runtime_image || github.event.inputs.node_runtime_image || 'node:22-slim' }}


  # Push control
  PUSH_IMAGES: ${{ github.event_name == 'push'
    || (github.event_name == 'workflow_call'    && inputs.push_images)
    || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_images == 'true') }}

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        service:
          - { name: account,    workdir: account,     dockerfile: account/Dockerfile }
          - { name: dashboard,  workdir: dashboard,   dockerfile: dashboard/Dockerfile }
          - { name: rag-server, workdir: rag-server,  dockerfile: rag-server/Dockerfile }
          - { name: xcontrol-init,    workdir: .,             dockerfile: xcontrol-init/Dockerfile }

    steps:
      # -------------------------------------------------------------
      # Checkout source
      # -------------------------------------------------------------
      - uses: actions/checkout@v4

      # -------------------------------------------------------------
      # Login to GHCR
      # -------------------------------------------------------------
      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      # -------------------------------------------------------------
      # Auto Tag
      # -------------------------------------------------------------
      - name: Generate Auto Tags
        id: meta
        uses: ./.github/actions/auto-tag
        with:
          image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}

      # -------------------------------------------------------------
      # Docker Buildx setup
      # -------------------------------------------------------------
      - uses: docker/setup-qemu-action@v3
      - uses: docker/setup-buildx-action@v3

      # -------------------------------------------------------------
      # Build service image
      # -------------------------------------------------------------
      - name: Build & Push Service Image
        id: build
        uses: docker/build-push-action@v6
        with:
          context: ${{ matrix.service.workdir }}
          file: ${{ matrix.service.dockerfile }}
          platforms: linux/amd64,linux/arm64
          push: ${{ env.PUSH_IMAGES == 'true' || env.PUSH_IMAGES == true }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            GO_RUNTIME_IMAGE=${{ env.GO_RUNTIME_IMAGE }}
            NODE_BUILDER_IMAGE=${{ env.NODE_BUILDER_IMAGE }}
            NODE_RUNTIME_IMAGE=${{ env.NODE_RUNTIME_IMAGE }}

      # -------------------------------------------------------------
      # Push to Docker Hub (optional)
      # -------------------------------------------------------------
      - name: Login to Docker Hub
        if: env.PUSH_IMAGES == 'true'
        uses: docker/login-action@v3
        with:
          registry: docker.io
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      # -------------------------------------------------------------
      # Re-tag & Push image to Docker Hub
      # -------------------------------------------------------------
      - name: Re-tag & Push Service Image (Docker Hub)
        if: env.PUSH_IMAGES == 'true'
        env:
          TARGET_NS: ${{ inputs.dockerhub_namespace || github.event.inputs.dockerhub_namespace || 'cloudneutral' }}
        run: |
          set -euo pipefail

          SERVICE="${{ matrix.service.name }}"
          ORIGIN_IMG="${{ env.REGISTRY }}/${{ env.ORG }}/${SERVICE}@${{ steps.build.outputs.digest }}"
          TARGET_REPO="docker.io/${TARGET_NS}/${SERVICE}"

          TAG="latest"
          docker pull "$ORIGIN_IMG"
          docker tag "$ORIGIN_IMG" "$TARGET_REPO:$TAG"
          docker push "$TARGET_REPO:$TAG"

  Security:
    runs-on: ubuntu-latest
    needs: build

    strategy:
      matrix:
        service:
          - { name: dashboard,  workdir: dashboard,   dockerfile: dashboard/Dockerfile }
          - { name: account,    workdir: account,     dockerfile: account/Dockerfile }
          - { name: rag-server, workdir: rag-server,  dockerfile: rag-server/Dockerfile }
          - { name: xcontrol-init,    workdir: .,             dockerfile: xcontrol-init/Dockerfile }

    steps:
      # -------------------------------------------------------------
      # Checkout source
      # -------------------------------------------------------------
      - uses: actions/checkout@v4

      # -------------------------------------------------------------
      # SBOM Generation
      # -------------------------------------------------------------
      - uses: anchore/sbom-action@v0
        with:
          image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
          output-file: sbom.spdx.json

      - uses: actions/upload-artifact@v4
        with:
          name: sbom-${{ matrix.service.name }}
          path: sbom.spdx.json

      # -------------------------------------------------------------
      # Trivy Vulnerability Scan
      # -------------------------------------------------------------
      - uses: aquasecurity/trivy-action@0.28.0
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
          severity: HIGH,CRITICAL
          exit-code: '1'

      # -------------------------------------------------------------
      # Cosign Signing
      # -------------------------------------------------------------
      - uses: sigstore/cosign-installer@v3
        with:
          cosign-release: 'v2.4.1'

      - name: Cosign Sign Image
        env:
          COSIGN_EXPERIMENTAL: "true"
        run: |
          IMG=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
          cosign sign --yes "$IMG"
