import groovy.json.JsonOutput

String shellQuote(String value) {
  return "'" + value.replace("'", "'\"'\"'") + "'"
}

pipeline {
  agent any

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(numToKeepStr: '30'))
  }

  parameters {
    string(name: 'GIT_REF', defaultValue: 'main', description: 'Git branch, tag, or commit to build.')
    string(name: 'IMAGE_TAG', defaultValue: '', description: 'Optional Harbor image tag override. Defaults to <branch>-<commit12>-<buildNumber>.')
    string(name: 'HARBOR_REGISTRY', defaultValue: '10.2.1.3:18082', description: 'Harbor registry address reachable from the Jenkins agent.')
    string(name: 'HARBOR_PROJECT', defaultValue: 'likei', description: 'Harbor project name.')
    string(name: 'HARBOR_CREDENTIALS_ID', defaultValue: 'likei-harbor-robot', description: 'Jenkins username/password credentials id for Harbor.')
    string(name: 'DOCKER_PLATFORM', defaultValue: 'linux/amd64', description: 'Docker build platform.')
  }

  environment {
    DOCKER_BUILDKIT = '1'
  }

  stages {
    stage('Checkout') {
      steps {
        checkout scm
        script {
          if (params.GIT_REF?.trim()) {
            sh """#!/usr/bin/env bash
set -euo pipefail
git fetch --all --tags --prune
git checkout --force ${shellQuote(params.GIT_REF.trim())}
"""
          }
        }
        sh 'mkdir -p ci-out'
      }
    }

    stage('Resolve Inputs') {
      steps {
        script {
          def branch = (env.BRANCH_NAME ?: env.GIT_BRANCH ?: 'manual').replaceAll('[^0-9A-Za-z._-]+', '-')
          env.RESOLVED_GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
          env.RESOLVED_GIT_COMMIT_SHORT = sh(returnStdout: true, script: 'git rev-parse --short=12 HEAD').trim()
          env.RESOLVED_IMAGE_TAG = params.IMAGE_TAG?.trim() ? params.IMAGE_TAG.trim() : "${branch}-${env.RESOLVED_GIT_COMMIT_SHORT}-${env.BUILD_NUMBER}"
          writeFile(
            file: 'ci-out/request.json',
            text: JsonOutput.prettyPrint(JsonOutput.toJson([
              repo: 'chatapp3-golang',
              gitRef: params.GIT_REF?.trim() ?: 'main',
              commit: env.RESOLVED_GIT_COMMIT,
              imageTag: env.RESOLVED_IMAGE_TAG,
            ])) + '\n',
          )
        }
      }
    }

    stage('Login Harbor') {
      steps {
        withCredentials([usernamePassword(credentialsId: params.HARBOR_CREDENTIALS_ID, usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASS')]) {
          sh '''#!/usr/bin/env bash
set -euo pipefail
printf '%s' "$HARBOR_PASS" | docker login "$HARBOR_REGISTRY" -u "$HARBOR_USER" --password-stdin
'''
        }
      }
    }

    stage('Build And Push') {
      steps {
        script {
          def imageRef = "${params.HARBOR_REGISTRY}/${params.HARBOR_PROJECT}/golang:${env.RESOLVED_IMAGE_TAG}"
          sh """#!/usr/bin/env bash
set -euo pipefail
DOCKER_PLATFORM='${params.DOCKER_PLATFORM}' ./ci/build-image.sh '${imageRef}' '${env.RESOLVED_GIT_COMMIT_SHORT}'
docker push '${imageRef}'
"""
          def digest = sh(returnStdout: true, script: "docker image inspect '${imageRef}' --format '{{index .RepoDigests 0}}'").trim()
          def serviceImages = [golang: digest]
          writeFile(file: 'ci-out/service-images.json', text: JsonOutput.prettyPrint(JsonOutput.toJson(serviceImages)) + '\n')
          writeFile(
            file: 'ci-out/deploy-params.json',
            text: JsonOutput.prettyPrint(JsonOutput.toJson([
              components: ['chatapp3-golang'],
              ref: env.RESOLVED_GIT_COMMIT,
              serviceImages: serviceImages,
            ])) + '\n',
          )
          writeFile(
            file: 'ci-out/build-metadata.json',
            text: JsonOutput.prettyPrint(JsonOutput.toJson([
              repo: 'chatapp3-golang',
              gitRef: params.GIT_REF?.trim() ?: 'main',
              commit: env.RESOLVED_GIT_COMMIT,
              imageTag: env.RESOLVED_IMAGE_TAG,
              serviceImages: serviceImages,
            ])) + '\n',
          )
        }
      }
    }
  }

  post {
    always {
      archiveArtifacts artifacts: 'ci-out/*.json', fingerprint: true, allowEmptyArchive: false
    }
  }
}
