stages:
  - quality
  - build
  - deploy

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

default:
  interruptible: true

variables:
  IMAGE_REPOSITORY: ""
  REGISTRY_HOST: ""
  REGISTRY_USER: ""
  REGISTRY_PASSWORD: ""

# --- Quality ---

lint:
  stage: quality
  image: node:20-alpine
  before_script:
    - corepack enable pnpm
    - pnpm install --frozen-lockfile
  script:
    - pnpm check
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

test:
  stage: quality
  image: node:20-alpine
  before_script:
    - corepack enable pnpm
    - pnpm install --frozen-lockfile
  script:
    - pnpm test:coverage
  coverage: '/Stmts\s*:\s*(\d+(?:\.\d+)?%)/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
    paths:
      - coverage/lcov.info
    expire_in: 1 week
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

sonarqube:
  stage: quality
  needs: [test]
  image:
    name: sonarsource/sonar-scanner-cli:latest
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
    GIT_DEPTH: "0"
  cache:
    key: sonar-cache
    paths:
      - .sonar/cache
  script:
    - sonar-scanner
      -Dsonar.host.url="${SONAR_HOST_URL}"
      -Dsonar.token="${SONAR_TOKEN}"
  allow_failure: true
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

# --- Build (Kaniko) ---

build-image:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:v1.23.2-debug
    entrypoint: [""]
  script:
    - |
      set -euo pipefail

      IMAGE_REPO="${CI_REGISTRY_IMAGE:-${IMAGE_REPOSITORY:-}}"
      if [ -z "${IMAGE_REPO}" ]; then
        echo "ERROR: CI_REGISTRY_IMAGE is empty."
        echo "Set CI/CD variable IMAGE_REPOSITORY (ex: registry.taaazzz-prog.fr/root/missioflow-site)"
        exit 1
      fi

      # Extraire le host depuis l'image cible (registry réel de destination)
      EFFECTIVE_REGISTRY=$(echo "$IMAGE_REPO" | cut -d'/' -f1)
      EFFECTIVE_REGISTRY_USER="${REGISTRY_USER:-${CI_REGISTRY_USER:-}}"
      EFFECTIVE_REGISTRY_PASSWORD="${REGISTRY_PASSWORD:-${CI_REGISTRY_PASSWORD:-}}"

      if [ -z "${EFFECTIVE_REGISTRY_USER}" ] || [ -z "${EFFECTIVE_REGISTRY_PASSWORD}" ]; then
        echo "ERROR: Missing registry credentials (REGISTRY_USER / REGISTRY_PASSWORD)."
        exit 1
      fi

      IMAGE_TAG="${CI_COMMIT_SHORT_SHA}"
      DEST_ARGS="--destination ${IMAGE_REPO}:${IMAGE_TAG}"

      if [ "${CI_COMMIT_BRANCH:-}" = "main" ]; then
        DEST_ARGS="${DEST_ARGS} --destination ${IMAGE_REPO}:latest"
      fi

      mkdir -p /kaniko/.docker
      printf '{"auths":{"%s":{"username":"%s","password":"%s"}}}\n' \
        "$EFFECTIVE_REGISTRY" "$EFFECTIVE_REGISTRY_USER" "$EFFECTIVE_REGISTRY_PASSWORD" > /kaniko/.docker/config.json

      /kaniko/executor \
        --context "${CI_PROJECT_DIR}" \
        --dockerfile "${CI_PROJECT_DIR}/Dockerfile" \
        ${DEST_ARGS}
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

# --- Deploy (SSH vers OVH) ---

deploy-ovh:
  stage: deploy
  tags:
    - local
  # Note : le tag 'local' matche deux runners — runner-docker (Alpine,
  # apk) et runner-local (shell Ubuntu, apt-get). Le before_script
  # detecte le gestionnaire de paquets dispo et installe bash +
  # openssh-client via celui qui convient. Sur Ubuntu shell, ces outils
  # sont generalement deja presents, on skip l install si c'est le cas.
  image: alpine:3.20
  needs:
    - job: build-image
  variables:
    STACK_FILE: missioflow-stack.yml
    OVH_SSH_PORT: "22"
  before_script:
    - |
      if command -v apk >/dev/null 2>&1; then
        apk add --no-cache bash openssh-client
      elif ! command -v ssh >/dev/null 2>&1; then
        # Ubuntu shell runner sans openssh-client — fallback apt-get
        # (necessite que le runner ait sudo NOPASSWD ou tourne en root)
        if command -v sudo >/dev/null 2>&1; then
          sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends openssh-client
        else
          apt-get update -qq && apt-get install -y --no-install-recommends openssh-client
        fi
      fi
    - eval "$(ssh-agent -s)"
    - |
      KEY_B64="${OVH_SSH_PRIVATE_KEY_B64:-${OVH_SSH_PRIVATE_KEY_B6:-}}"
      if [ -n "${KEY_B64:-}" ] && [ -f "${KEY_B64}" ]; then
        chmod 600 "${KEY_B64}"
        export OVH_SSH_KEY_PATH="${KEY_B64}"
        ssh-add "${OVH_SSH_KEY_PATH}"
      elif [ -n "${KEY_B64:-}" ]; then
        printf '%s' "${KEY_B64}" | tr -d '\r\n\t ' | base64 -d > /tmp/ovh_ci_ssh_key
        chmod 600 /tmp/ovh_ci_ssh_key
        export OVH_SSH_KEY_PATH="/tmp/ovh_ci_ssh_key"
        ssh-add "${OVH_SSH_KEY_PATH}"
      elif [ -n "${OVH_SSH_PRIVATE_KEY:-}" ]; then
        printf '%s' "${OVH_SSH_PRIVATE_KEY}" | tr -d '\r' > /tmp/ovh_ci_ssh_key
        chmod 600 /tmp/ovh_ci_ssh_key
        export OVH_SSH_KEY_PATH="/tmp/ovh_ci_ssh_key"
        ssh-add "${OVH_SSH_KEY_PATH}"
      else
        echo "ERROR: Missing OVH_SSH_PRIVATE_KEY_B64 or OVH_SSH_PRIVATE_KEY."
        exit 1
      fi
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan -p "$OVH_SSH_PORT" "$OVH_SSH_HOST" >> ~/.ssh/known_hosts
    - chmod 600 ~/.ssh/known_hosts
  script:
    - |
      set -euo pipefail

      IMAGE_REPO="${CI_REGISTRY_IMAGE:-${IMAGE_REPOSITORY:-}}"
      if [ -z "${IMAGE_REPO}" ]; then
        echo "ERROR: IMAGE repository is not configured."
        exit 1
      fi

      EFFECTIVE_REGISTRY="${CI_REGISTRY:-${REGISTRY_HOST:-}}"
      EFFECTIVE_REGISTRY_USER="${CI_REGISTRY_USER:-${REGISTRY_USER:-}}"
      EFFECTIVE_REGISTRY_PASSWORD="${CI_REGISTRY_PASSWORD:-${REGISTRY_PASSWORD:-}}"

      if [ -z "${EFFECTIVE_REGISTRY}" ] || [ -z "${EFFECTIVE_REGISTRY_USER}" ] || [ -z "${EFFECTIVE_REGISTRY_PASSWORD}" ]; then
        echo "ERROR: Missing registry credentials for deploy."
        exit 1
      fi

      IMAGE_TAG="${CI_COMMIT_SHORT_SHA}"
      IMAGE_REF="${IMAGE_REPO}:${IMAGE_TAG}"
      REGISTRY_PASSWORD_B64="$(printf '%s' "$EFFECTIVE_REGISTRY_PASSWORD" | base64 | tr -d '\n')"

      # Remplacer de maniere deterministe l'image du service web par le tag du commit.
      # On ne depend pas d'un repo hardcode dans le fichier stack.
      sed -E "s|^([[:space:]]*image:[[:space:]]*).*$|\1${IMAGE_REF}|g" "$STACK_FILE" > /tmp/missioflow-stack-deploy.yml
      grep -n "^[[:space:]]*image:" /tmp/missioflow-stack-deploy.yml
      scp -P "$OVH_SSH_PORT" -i "$OVH_SSH_KEY_PATH" -o IdentitiesOnly=yes -o BatchMode=yes /tmp/missioflow-stack-deploy.yml "$OVH_SSH_USER@$OVH_SSH_HOST:/tmp/$STACK_FILE"

      ssh -p "$OVH_SSH_PORT" -i "$OVH_SSH_KEY_PATH" -o IdentitiesOnly=yes -o BatchMode=yes "$OVH_SSH_USER@$OVH_SSH_HOST" "set -euo pipefail; \
        printf '%s' '$REGISTRY_PASSWORD_B64' | base64 -d | docker login '$EFFECTIVE_REGISTRY' -u '$EFFECTIVE_REGISTRY_USER' --password-stdin; \
        docker pull '$IMAGE_REF'; \
        set -a; [ -f /opt/missioflow/.env ] && . /opt/missioflow/.env; set +a; \
        docker stack deploy -c '/tmp/$STACK_FILE' missioflow --with-registry-auth; \
        docker stack services missioflow"
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  environment:
    name: production
    url: https://missioflow.fr
