// Jenkinsfile — build + publish both images to the thinkserver:5000 registry.
//
//   ttrpg-tracker-firebase : root Dockerfile, nginx serving the static SPA,
//                            Firebase storage (config baked in at build time).
//   ttrpg-tracker-sqlite   : docker/Dockerfile, Caddy + Node, server/SQLite
//                            storage (REACT_APP_STORAGE=server).
//
// Requirements on the Jenkins agent:
//   * Docker CLI available, agent user in the docker group (or DooD socket).
//   * thinkserver:5000 reachable and trusted by the Docker daemon. If it is a
//     plain-HTTP registry, add it to /etc/docker/daemon.json on the AGENT host:
//       { "insecure-registries": ["thinkserver:5000"] }   (then restart docker)
//
// Jenkins credentials this pipeline expects:
//   * ttrpg-firebase-env-local  (Secret file)  — the .env.local contents with
//     REACT_APP_FIREBASE_* values. Baked into the firebase image at build time.
//   * thinkserver-registry      (Username/pw)  — OPTIONAL. Only needed if the
//     registry requires auth; the login stage is guarded below.

pipeline {
  agent any

  options {
    timestamps()
    disableConcurrentBuilds()
    timeout(time: 30, unit: 'MINUTES')
  }

  parameters {
    string(name: 'TRACKER_APP_ID',
           defaultValue: 'ttrpg-initiative-tracker-default',
           description: 'Firestore/app namespace baked into the SQLite image (REACT_APP_TRACKER_APP_ID).')
    booleanParam(name: 'PUSH_LATEST', defaultValue: true,
           description: 'Also tag and push :latest in addition to the commit-SHA tag.')
    booleanParam(name: 'REGISTRY_AUTH', defaultValue: false,
           description: 'Enable docker login using the thinkserver-registry credential.')
    booleanParam(name: 'REDEPLOY_PORTAINER', defaultValue: true,
           description: 'After pushing, POST to the Portainer stack webhooks to re-pull and redeploy.')
  }

  environment {
    REGISTRY       = 'thinkserver:5000'
    FIREBASE_IMAGE = "${REGISTRY}/ttrpg-tracker-firebase"
    SQLITE_IMAGE   = "${REGISTRY}/ttrpg-tracker-sqlite"
    DOCKER_BUILDKIT = '1'
  }

  stages {
    stage('Checkout') {
      steps {
        checkout scm
        script {
          env.SHORT_SHA = sh(returnStdout: true, script: 'git rev-parse --short=8 HEAD').trim()
          // Only build/push on main. BRANCH_NAME is set by Multibranch jobs; it
          // is unset in a plain "Pipeline from SCM" job, which already only ever
          // checks out main, so treat unset as main too.
          env.IS_MAIN = (env.BRANCH_NAME == null || env.BRANCH_NAME == 'main').toString()
          if (env.IS_MAIN != 'true') {
            echo "Branch '${env.BRANCH_NAME}' is not main — skipping image build/push."
          } else {
            echo "Building tag ${env.SHORT_SHA} (build #${env.BUILD_NUMBER})"
          }
        }
      }
    }

    stage('Registry login') {
      when { allOf { expression { env.IS_MAIN == 'true' }; expression { return params.REGISTRY_AUTH } } }
      steps {
        withCredentials([usernamePassword(credentialsId: 'thinkserver-registry',
                                           usernameVariable: 'REG_USER',
                                           passwordVariable: 'REG_PASS')]) {
          sh 'echo "$REG_PASS" | docker login "$REGISTRY" -u "$REG_USER" --password-stdin'
        }
      }
    }

    stage('Build firebase image') {
      when { expression { env.IS_MAIN == 'true' } }
      steps {
        // Firebase config is compiled into the static bundle, so it must exist
        // at build time. Inject .env.local from the Jenkins secret file, then
        // the root Dockerfile's `COPY .env.local .env` picks it up.
        withCredentials([file(credentialsId: 'ttrpg-firebase-env-local', variable: 'FIREBASE_ENV')]) {
          sh '''
            cp "$FIREBASE_ENV" .env.local
            docker build \
              -f Dockerfile \
              -t "$FIREBASE_IMAGE:$SHORT_SHA" \
              .
          '''
        }
      }
    }

    stage('Build sqlite image') {
      when { expression { env.IS_MAIN == 'true' } }
      steps {
        // Server/SQLite build. BuildKit is required (syntax directive + cache
        // mount in docker/Dockerfile). Context is the repo root.
        sh '''
          docker build \
            -f docker/Dockerfile \
            --build-arg REACT_APP_TRACKER_APP_ID="$TRACKER_APP_ID" \
            -t "$SQLITE_IMAGE:$SHORT_SHA" \
            .
        '''
      }
    }

    stage('Tag latest') {
      when { allOf { expression { env.IS_MAIN == 'true' }; expression { return params.PUSH_LATEST } } }
      steps {
        sh '''
          docker tag "$FIREBASE_IMAGE:$SHORT_SHA" "$FIREBASE_IMAGE:latest"
          docker tag "$SQLITE_IMAGE:$SHORT_SHA"   "$SQLITE_IMAGE:latest"
        '''
      }
    }

    stage('Push') {
      when { expression { env.IS_MAIN == 'true' } }
      steps {
        sh '''
          docker push "$FIREBASE_IMAGE:$SHORT_SHA"
          docker push "$SQLITE_IMAGE:$SHORT_SHA"
        '''
        script {
          if (params.PUSH_LATEST) {
            sh '''
              docker push "$FIREBASE_IMAGE:latest"
              docker push "$SQLITE_IMAGE:latest"
            '''
          }
        }
      }
    }

    stage('Redeploy (Portainer webhooks)') {
      when { allOf { expression { env.IS_MAIN == 'true' }; expression { return params.REDEPLOY_PORTAINER } } }
      steps {
        // Webhook URLs are Secret-text credentials, so they never appear in the
        // repo and Jenkins masks them in the console. They are bound to shell
        // env vars and referenced inside a single-quoted sh block, so Groovy
        // never interpolates the value into the pipeline log.
        withCredentials([
          string(credentialsId: 'portainer-webhook-firebase', variable: 'WEBHOOK_FIREBASE'),
          string(credentialsId: 'portainer-webhook-sqlite',   variable: 'WEBHOOK_SQLITE'),
        ]) {
          sh '''
            set +x
            echo "Triggering Portainer redeploy (firebase stack)"
            curl -fsS -X POST --retry 3 --retry-delay 5 "$WEBHOOK_FIREBASE"
            echo "Triggering Portainer redeploy (sqlite stack)"
            curl -fsS -X POST --retry 3 --retry-delay 5 "$WEBHOOK_SQLITE"
          '''
        }
      }
    }
  }

  post {
    always {
      // Never leave Firebase secrets in the workspace or log out cleanly.
      sh 'rm -f .env.local || true'
      sh 'docker logout "$REGISTRY" || true'
    }
    success {
      echo "Pushed ${FIREBASE_IMAGE}:${SHORT_SHA} and ${SQLITE_IMAGE}:${SHORT_SHA}"
    }
  }
}
