# Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

---
{{- $appIdentifier :=  "sv-app" }}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ $appIdentifier }}
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "splice-util-lib.default-labels" (set . "app" $appIdentifier) | nindent 4 }}
    migration: {{ .Values.migration.id | quote }}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: {{ $appIdentifier }}
  strategy:
    type: "Recreate"
  template:
    metadata:
      annotations:
        {{- toYaml .Values.pod.annotations | nindent 8 }}
      labels:
        {{- include "splice-util-lib.default-labels" (set . "app" $appIdentifier) | nindent 8 }}
        migration: {{ .Values.migration.id | quote }}
    spec:
      {{- include "splice-util-lib.service-account" .Values | nindent 6 }}
      securityContext:
        runAsUser: 1001
        runAsGroup: 1001
        fsGroup: 1001
      containers:
        - name: sv-app
          image: "{{ .Values.imageRepo }}/sv-app:{{ .Chart.AppVersion }}{{ ((.Values.imageDigests).sv_app) }}"
          {{- with .Values.imagePullPolicy }}
          imagePullPolicy: {{ . }}
          {{- end }}
          env:
            - name: JAVA_TOOL_OPTIONS
              value: {{ .Values.defaultJvmOptions }} {{ .Values.additionalJvmOptions }}
            {{- include "splice-util-lib.auth0-env-vars" (dict "appName" "sv" "keyName" "sv" "fixedTokens" .Values.cluster.fixedTokens) | indent 12}}
            {{- include "splice-util-lib.auth0-user-env-var" (dict "appName" "validator" "keyName" "validator") | indent 12}}
            - name: SPLICE_APP_SV_PARTICIPANT_ADDRESS
              value: {{ .Values.participantAddress | quote }}
            {{- if .Values.migration.migrating }}
            - name: ADDITIONAL_CONFIG_SV_ONBOARDING
              value: |
                _onboarding {
                  type = "domain-migration"
                  dump-file-path = "/domain-upgrade-dump/domain_migration_dump.json"
                }
            {{- else if .Values.joinWithKeyOnboarding }}
            - name: ADDITIONAL_CONFIG_SV_ONBOARDING
              value: |
                _onboarding {
                  type = "join-with-key"
                  sv-client.admin-api.url = "{{ .Values.joinWithKeyOnboarding.sponsorApiUrl }}"
                }
            - name: SPLICE_APP_SV_PUBLIC_KEY
              valueFrom:
                secretKeyRef:
                  key: public
                  name: "splice-app-sv-key"
                  optional: false
            - name: SPLICE_APP_SV_PRIVATE_KEY
              valueFrom:
                secretKeyRef:
                  key: private
                  name: "splice-app-sv-key"
                  optional: false
            {{- else }}
              {{- if eq .Values.onboardingType "found-dso" }}
            - name: SPLICE_APP_SV_IS_DEV_NET
              value: {{ .Values.isDevNet | quote }}
                {{- if .Values.initialAmuletPrice }}
            - name: SPLICE_APP_SV_INITIAL_AMULET_PRICE
              value: {{ .Values.initialAmuletPrice | quote }}
                {{- end }}
              {{- end }}
              {{ if .Values.onboardingType }}
            - name: SPLICE_APP_SV_ONBOARDING_TYPE
              value: {{ .Values.onboardingType }}
              {{- end }}
            {{- end }}
            {{- if .Values.onboardingName }}
            - name: SPLICE_APP_SV_ONBOARDING_NAME
              value: {{ .Values.onboardingName }}
            {{- end }}
            {{- if .Values.onboardingFoundingSvRewardWeightBps }}
            - name: SPLICE_APP_SV_SV1_REWARD_WEIGHT
              value: {{ .Values.onboardingFoundingSvRewardWeightBps | quote }}
            {{- end }}
            {{- if .Values.onboardingRoundZeroDuration }}
            - name: SPLICE_APP_SV_ROUND_ZERO_DURATION
              value: {{ .Values.onboardingRoundZeroDuration | quote }}
            {{- end }}
            {{- if .Values.initialRound }}
            - name: SPLICE_APP_SV_INITIAL_ROUND
              value: {{ .Values.initialRound | quote }}
            {{- end }}
            {{- if .Values.initialTickDuration }}
            - name: SPLICE_APP_SV_INITIAL_TICK_DURATION
              value: {{ .Values.initialTickDuration | quote }}
            {{- end }}
            {{- if .Values.initialHoldingFee }}
            - name: SPLICE_APP_SV_INITIAL_HOLDING_FEE
              value: {{ .Values.initialHoldingFee | quote }}
            {{- end }}
            {{- if .Values.initialAmuletPrice }}
            - name: SPLICE_APP_SV_INITIAL_AMULET_PRICE_VOTE
              value: {{ .Values.initialAmuletPrice | quote }}
            {{- end }}
            - name: SPLICE_APP_SV_AUTH_AUDIENCE
              value: {{ .Values.auth.audience | quote }}
            - name: SPLICE_APP_SV_AUTH_JWKS_URL
              value: {{ .Values.auth.jwksUrl | quote }}
            {{ if (.Values.auth.jwks).connectionTimeout }}
            - name: SPLICE_APP_VALIDATOR_AUTH_JWKS_CONNECTION_TIMEOUT
              value: {{ .Values.auth.jwks.connectionTimeout | quote }}
            {{ end }}
            {{ if (.Values.auth.jwks).readTimeout }}
            - name: SPLICE_APP_VALIDATOR_AUTH_JWKS_READ_TIMEOUT
              value: {{ .Values.auth.jwks.readTimeout | quote }}
            {{ end }}
            {{ if .Values.disableIngestUpdateHistoryFromParticipantBegin }}
            - name: ADDITIONAL_CONFIG_UPDATE_HISTORY_INGESTION
              value: |
                canton.sv-apps.sv.ingest-update-history-from-participant-begin = false
            {{ end }}
            {{- with .Values.persistence }}
            - name: ADDITIONAL_CONFIG_PERSISTENCE
              value: |
                canton.sv-apps.sv.storage {
                  config {
                    properties = {
                      databaseName = "{{ .databaseName }}"
                      currentSchema = "{{ .schema }}"
                      serverName = "{{ .host }}"
                      portNumber = {{ .port }}
                      user = "{{ .user }}"
                      password = ${SPLICE_APP_POSTGRES_PASSWORD}
                    }
                  }
                }
            - name: SPLICE_APP_POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: {{ $.Values.persistence.secretName }}
                  key: postgresPassword
            {{- end }}
            - name: ADDITIONAL_CONFIG_MIGRATION_ID
              value: |
                canton.sv-apps.sv {
                  domain-migration-id = {{ .Values.migration.id }}
                }
            {{ if hasKey .Values.migration "legacyId" }}
            - name: ADDITIONAL_CONFIG_LEGACY_MIGRATION_ID
              value: |
                canton.sv-apps.sv {
                  legacy-migration-id = {{ .Values.migration.legacyId }}
                }
            {{ end }}
            - name: ADDITIONAL_CONFIG_GLOBAL_DOMAIN_UPGRADE_DUMP_PATH
              value: |
                canton.sv-apps.sv.domain-migration-dump-path = "/domain-upgrade-dump/domain_migration_dump.json"
            {{- with .Values.domain }}
            - name: ADDITIONAL_CONFIG_SV_DOMAIN
              #TODO(#930) - switch to port 443 https://github.com/DACH-NY/canton/issues/23835
              value: |
                canton.sv-apps.sv.local-synchronizer-node {
                  sequencer {
                    {{- if .enableBftSequencer }}
                    is-bft-sequencer = true
                    {{- end }}
                    admin-api {
                      address = {{ .sequencerAddress | quote }}
                      port = 5009
                    }
                    internal-api {
                      address = {{ .sequencerAddress | quote }}
                      port = 5008
                    }
                    external-public-api-url = {{ .sequencerPublicUrl | quote }}
                    {{- if .sequencerPruningConfig.enabled }}
                    pruning {
                      pruning-interval = {{ .sequencerPruningConfig.pruningInterval | quote }}
                      retention-period = {{ .sequencerPruningConfig.retentionPeriod | quote }}
                    }
                    {{- end }}
                  }
                  mediator {
                    admin-api {
                      address = {{ .mediatorAddress | quote }}
                      port = 5007
                    }
                  }
                }
            {{- end }}
            {{- if .Values.decentralizedSynchronizerUrl }}
            - name: SPLICE_APP_SV_GLOBAL_DOMAIN_URL
              value: {{ .Values.decentralizedSynchronizerUrl | quote }}
            {{- end }}
            {{- if (.Values.cometBFT).enabled }}
            - name: SPLICE_APP_SV_COMETBFT_ENABLED
              value: {{ (.Values.cometBFT).enabled | quote }}
            {{- end }}
            {{- if (.Values.cometBFT).connectionUri }}
            - name: SPLICE_APP_SV_COMETBFT_CONNECTION_URI
              value: {{ (.Values.cometBFT).connectionUri }}
            {{- end }}
            {{- if (.Values.cometBFT).externalGovernanceKey }}
            - name: ADDITIONAL_CONFIG_SV_COMETBFT_GOVERNANCE_KEY
              value: |
                _comet_bft_config {
                  governance-key {
                    public-key = ${?SPLICE_APP_SV_COMETBFT_GOVERNANCE_PUBLIC_KEY}
                    private-key = ${?SPLICE_APP_SV_COMETBFT_GOVERNANCE_PRIVATE_KEY}
                  }
                }
            - name: SPLICE_APP_SV_COMETBFT_GOVERNANCE_PUBLIC_KEY
              valueFrom:
                secretKeyRef:
                  key: public
                  name: "splice-app-sv-cometbft-governance-key"
                  optional: false
            - name: SPLICE_APP_SV_COMETBFT_GOVERNANCE_PRIVATE_KEY
              valueFrom:
                secretKeyRef:
                  key: private
                  name: "splice-app-sv-cometbft-governance-key"
                  optional: false
            {{- end }}
            - name: SPLICE_APP_UI_NETWORK_NAME
              value: {{ .Values.spliceInstanceNames.networkName | quote }}
            - name: SPLICE_APP_UI_NETWORK_FAVICON_URL
              value: {{ .Values.spliceInstanceNames.networkFaviconUrl | quote }}
            - name: SPLICE_APP_UI_AMULET_NAME
              value: {{ .Values.spliceInstanceNames.amuletName | quote }}
            - name: SPLICE_APP_UI_AMULET_NAME_ACRONYM
              value: {{ .Values.spliceInstanceNames.amuletNameAcronym | quote }}
            - name: SPLICE_APP_UI_NAME_SERVICE_NAME
              value: {{ .Values.spliceInstanceNames.nameServiceName | quote }}
            - name: SPLICE_APP_UI_NAME_SERVICE_NAME_ACRONYM
              value: {{ .Values.spliceInstanceNames.nameServiceNameAcronym | quote }}
            {{- range $ii, $onboarding := .Values.expectedValidatorOnboardings }}
            - name: ADDITIONAL_CONFIG_VALIDATOR_ONBOARDING_{{ $ii }}
              value: |
                canton.sv-apps.sv.expected-validator-onboardings.{{ $ii }} = {
                  secret = ${SPLICE_APP_VALIDATOR_ONBOARDING_SECRET_{{ $ii }}}
                  expires-in = {{ $onboarding.expiresIn }}
                }
            - name: SPLICE_APP_VALIDATOR_ONBOARDING_SECRET_{{ $ii }}
              valueFrom: {{ $onboarding.secretFrom | toYaml | nindent 16 }}
            {{- end }}
            {{- range $ii, $sv := .Values.approvedSvIdentities }}
            - name: ADDITIONAL_CONFIG_APPROVED_SV_IDENTITY_{{ $ii }}
              value: |
                canton.sv-apps.sv.approved-sv-identities.{{ $ii }} = {
                  name = {{ $sv.name | quote }}
                  public-key = {{ $sv.publicKey | quote }}
                  reward-weight-bps = {{ $sv.rewardWeightBps | quote }}
                }
            {{- end }}
            {{- with .Values.identitiesExport }}
            - name: ADDITIONAL_CONFIG_SPLICE_APP_SV_IDENTITIES_EXPORT
              value: |
                canton.sv-apps.sv.identities-dump = {
                  type = gcp
                  bucket {
                    project-id = {{ .bucket.projectId }}
                    bucket-name = {{ .bucket.bucketName }}
                    credentials {
                      type = service-account
                      json-credentials = ${SPLICE_APP_SV_IDS_BACKUP_BUCKET_SERVICE_ACCOUNT_CREDENTIALS}
                    }
                  }
                  prefix = {{ .prefix | quote }}
                }
            - name: SPLICE_APP_SV_IDS_BACKUP_BUCKET_SERVICE_ACCOUNT_CREDENTIALS
              valueFrom:
                secretKeyRef:
                  key: "json-credentials"
                  name: {{ .bucket.secretName }}
            {{- end }}
            {{- with .Values.participantIdentitiesDumpImport }}
            - name: ADDITIONAL_CONFIG_SPLICE_APP_SV_PARTICIPANT_IDENTITIES_DUMP_IMPORT
              value: |
                canton.sv-apps.sv.participant-bootstrapping-dump {
                  type = file
                  file = /participant-bootstrapping-dump/content
                }
            {{- end }}
            - name: ADDITIONAL_CONFIG_SCAN_PUBLIC_URL
              value: |
                canton.sv-apps.sv.scan.public-url = {{ .Values.scan.publicUrl | quote }}
                canton.sv-apps.sv.scan.internal-url = {{ .Values.scan.internalUrl | quote }}
            {{- if .Values.disableOnboardingParticipantPromotionDelay }}
            - name: ADDITIONAL_CONFIG_DISABLE_ONBOARDING_PARTICIPANT_PROMOTION_DELAY
              value: |
                canton.sv-apps.sv.enable-onboarding-participant-promotion-delay = false
            {{- end }}
            {{- range $ii, $sv := .Values.extraBeneficiaries }}
            - name: ADDITIONAL_CONFIG_BENEFICIARIES_{{ $ii }}
              value: |
                canton.sv-apps.sv.extra-beneficiaries.{{ $ii }} = {
                  beneficiary = {{ $sv.beneficiary | quote }}
                  weight = {{ $sv.weight }}
                }
            {{- end }}
            {{- with .Values.onboardingPollingInterval }}
            - name: ADDITIONAL_CONFIG_ONBOARDING_POLLING_INTERVAL
              value: |
                canton.sv-apps.sv.onboarding-polling-interval = {{ . }}
            {{- end }}
            {{- with .Values.initialSynchronizerFeesConfig }}
            - name: ADDITIONAL_CONFIG_DOMAIN_FEES
              value: |
               canton.sv-apps.sv.onboarding.initial-synchronizer-fees-config {
                 extra-traffic-price = {{ printf "%f" .extraTrafficPrice }}
                 min-topup-amount = {{ printf "%.0f" .minTopupAmount }}
                 base-rate-burst-amount = {{ printf "%.0f" .baseRateBurstAmount }}
                 base-rate-burst-window = {{ printf "%.0fm" .baseRateBurstWindowMins | quote }}
                 read-vs-write-scaling-factor = {{ printf "%.0f" .readVsWriteScalingFactor }}
               }
            {{- end }}
            {{- if .Values.initialPackageConfigJson }}
            - name: ADDITIONAL_CONFIG_INITIAL_PACKAGE_CONFIG
              value: |
                canton.sv-apps.sv.onboarding.initial-package-config = {{ .Values.initialPackageConfigJson | quote }}
            {{- end }}
            - name: FAIL_ON_APP_VERSION_MISMATCH
              value: {{ .Values.failOnAppVersionMismatch | quote }}
            {{- include "splice-util-lib.additional-env-vars" .Values.additionalEnvVars | indent 12}}
            {{- include "splice-util-lib.log-level" .Values | indent 12}}
            - name: SPLICE_APP_CONTACT_POINT
              value: {{ .Values.contactPoint | default "" | quote }}
            - name: SPLICE_APP_SV_PARTICIPANT_IDENTIFIER
              value: {{ .Values.nodeIdentifier | quote }}
            - name: SPLICE_APP_SV_SEQUENCER_IDENTIFIER
              value: {{ .Values.nodeIdentifier | quote }}
            - name: SPLICE_APP_SV_MEDIATOR_IDENTIFIER
              value: {{ .Values.nodeIdentifier | quote }}
            {{- if .Values.delegatelessAutomationExpectedTaskDuration }}
            - name: SPLICE_APP_EXPECTED_TASK_DURATION
              value: {{ .Values.delegatelessAutomationExpectedTaskDuration | quote }}
            {{- end }}
            {{- if .Values.delegatelessAutomationExpiredRewardCouponBatchSize }}
            - name: SPLICE_APP_EXPIRED_REWARD_COUPON_BATCH_SIZE
              value: {{ .Values.delegatelessAutomationExpiredRewardCouponBatchSize | quote }}
            {{- end }}
            {{- if .Values.domain.skipInitialization }}
            - name: ADDITIONAL_CONFIG_SYNCHRONIZER_INITIALIZATION
              value: canton.sv-apps.sv.skip-synchronizer-initialization = true
            {{- end }}
            {{- with .Values.maxVettingDelay }}
            - name: ADDITIONAL_CONFIG_MAX_VETTING_DELAY
              value: canton.sv-apps.sv.max-vetting-delay = "{{ . }}"
            {{- end }}
          ports:
            - name: sv-api
              containerPort: 5014
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /api/sv/livez
              port: 5014
            initialDelaySeconds: {{ .Values.livenessProbeInitialDelaySeconds | default 60 }}
            periodSeconds: 60
            failureThreshold: 5
            timeoutSeconds: 10
          readinessProbe:
            httpGet:
              path: /api/sv/readyz
              port: 5014
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 5
            timeoutSeconds: 10
          {{- if or .Values.participantIdentitiesDumpImport .Values.migration.attachPvc }}
          volumeMounts:
          {{- with .Values.participantIdentitiesDumpImport }}
            - name: participant-bootstrapping-dump-volume
              mountPath: /participant-bootstrapping-dump
              readOnly: true
          {{- end }}
          {{- if .Values.migration.attachPvc }}
            - name: domain-upgrade-dump-volume
              mountPath: /domain-upgrade-dump
          {{- end }}
          {{- end }}
          {{- with .Values.resources }}
          resources: {{- toYaml . | nindent 12 }}
          {{- end }}
      initContainers:
        - name: {{ .Release.Name }}-init
          image: postgres:14
          env:
            - name: PGPASSWORD
              valueFrom:
                secretKeyRef:
                  key: postgresPassword
                  name: {{ .Values.persistence.secretName }}
          command:
            - 'bash'
            - '-c'
            - |
              until errmsg=$(psql -h {{ .Values.persistence.host }} -p {{ .Values.persistence.port }} --username=cnadmin --dbname=cantonnet -c 'create database {{ .Values.persistence.databaseName }}' 2>&1); do
                if [[ $errmsg == *"already exists"* ]]; then
                  echo "Database {{ .Values.persistence.databaseName }} already exists. Done."
                  break
                fi

                echo "trying to create postgres database {{ .Values.persistence.databaseName }}, last error: $errmsg";
                sleep 2;
              done
      volumes:
      {{- with .Values.participantIdentitiesDumpImport }}
        - name: participant-bootstrapping-dump-volume
          secret:
            secretName: {{ .secretName }}
      {{- end }}
      {{- if .Values.migration.attachPvc }}
        - name: domain-upgrade-dump-volume
          persistentVolumeClaim:
            claimName: {{ .Values.pvc.volumeName }}
      {{- end }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ $appIdentifier }}
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "splice-util-lib.default-labels" (set . "app" $appIdentifier) | nindent 4 }}
    migration: {{ .Values.migration.id | quote }}
spec:
  selector:
    app: {{ $appIdentifier }}
  ports:
    - name: sv-api
      port: 5014
      protocol: TCP
    - name: metrics
      port: 10013
      protocol: TCP
{{- if .Values.migration.attachPvc }}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: {{ .Values.pvc.volumeName }}
  namespace: {{ $.Release.Namespace }}
  annotations:
    helm.sh/resource-policy: keep
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20G
  storageClassName: {{ .Values.pvc.volumeStorageClass }}
{{- end }}
---
{{- if .Values.enablePostgresMetrics }}
{{- include "splice-util-lib.postgres-metrics" (dict "persistence" .Values.persistence "namespace" .Release.Namespace "nodeSelector" .Values.nodeSelector "affinity" .Values.affinity "tolerations" .Values.tolerations ) }}
{{- end}}
