package action

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/cluster-service-ng/pkg/template/render"
)

var (
	tidbDiagnosisTestTemplArgs = map[string]string{
		"ClusterId":       "1233438346465886",
		"SharedPoolId":    "1233438346465886",
		"ComponentId":     "3a219eb3",
		"ComponentType":   "diagnose-tidb",
		"ComponentGroup":  "db-3a219eb3-diagnose-tidb",
		"AuditLogConfig":  "logDir: /var/log/auditlog\ngracefulStopWaitSeconds: 27",
		"Image":           "385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/tidb:master-next-gen",
		"AuditLogImage":   "385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/audit-ng:c91e07382bbf5914ed9f81673bef1c23144b8972",
		"SlowLogImage":    "385595570414.dkr.ecr.us-west-2.amazonaws.com/third-party/busybox:1.34.1",
		"ImagePullPolicy": "IfNotPresent",
		"verifyCN":        "59accb4c",
		"TiKVWorkerURL":   "https://db-3a219eb3-tikv-worker-peer.tidb1233438346465886.svc:19000",
	}
)

func Test_RenderTiDBDiagnoseDeployment(t *testing.T) {
	tl := initTiDBDiagnoseTemplate(t)
	yamlStr, err := tl.Render("tidb_diagnosis_deployment", tidbDiagnosisTestTemplArgs)
	require.NoError(t, err)
	require.NotEmpty(t, yamlStr)
	assert.YAMLEq(t, `apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-3a219eb3-diagnose-tidb
  namespace: tidb1233438346465886
  labels:
    pingcap.com/group: db-3a219eb3-diagnose-tidb
    pingcap.com/component: diagnose-tidb
    pingcap.com/cluster: db
    tags.tidbcloud.com/shared-pool: '1233438346465886'
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      pingcap.com/group: db-3a219eb3-diagnose-tidb
      pingcap.com/component: diagnose-tidb
      pingcap.com/cluster: db
      tags.tidbcloud.com/shared-pool: '1233438346465886'
  template:
    metadata:
      labels:
        pingcap.com/group: db-3a219eb3-diagnose-tidb
        pingcap.com/component: diagnose-tidb
        pingcap.com/cluster: db
        tags.tidbcloud.com/component: diagnose-tidb
        tags.tidbcloud.com/resource-pool: '1233438346465886'
        tags.tidbcloud.com/shared-pool: '1233438346465886'
      annotations:
        prometheus.io/path: /metrics
        prometheus.io/port: "10080"
        prometheus.io/scrape: "true"
        tidb.auditlog.prometheus.io/port: "9090"
        tidb.auditlog.config: |
          logDir: /var/log/auditlog
          gracefulStopWaitSeconds: 27
    spec:
      priorityClassName: tidb-ng-component-critical
      serviceAccountName: tidb-cluster
      subdomain: db-3a219eb3-diagnose-tidb-peer
      containers:
      - name: tidb
        image: 385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/tidb:master-next-gen
        imagePullPolicy: IfNotPresent
        command:
        - /tidb-server
        - --config
        - /etc/tidb/config.toml
        env:
        - name: TZ
          value: UTC
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        ports:
        - containerPort: 4000
          hostPort: 4000
          name: mysql-client
          protocol: TCP
        - containerPort: 10080
          hostPort: 10080
          name: status
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          exec:
            command:
            - "curl"
            - "--cacert"
            - "/var/lib/tidb-tls/ca.crt"
            - "--cert"
            - "/var/lib/tidb-tls/tls.crt"
            - "--key"
            - "/var/lib/tidb-tls/tls.key"
            - "https://127.0.0.1:10080/status"
          timeoutSeconds: 1
        resources:
          requests:
            cpu: 2
            memory: 4Gi
          limits:
            cpu: 2
            memory: 4Gi
        securityContext:
          readOnlyRootFilesystem: true
          allowPrivilegeEscalation: false
          privileged: false
          capabilities:
            drop:
              - NET_RAW
        volumeMounts:
        - mountPath: /etc/tidb
          name: ti-config
        - mountPath: /var/log/auditlog
          name: ti-auditlog
        - mountPath: /var/lib/tidb-sql-tls
          name: ti-tidb-sql-tls
          readOnly: true
        - mountPath: /var/lib/tidb-tls
          name: ti-tls
          readOnly: true
        - name: tmp-volume
          mountPath: /tmp
      - name: auditlog
        image: 385595570414.dkr.ecr.us-west-2.amazonaws.com/tidbcloud/audit-ng:c91e07382bbf5914ed9f81673bef1c23144b8972
        imagePullPolicy: IfNotPresent
        command:
        - /audit-ng
        - server
        - --config
        - /etc/podinfo/audit-config.yaml
        env:
        - name: TZ
          value: UTC
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        ports:
        - containerPort: 9090
          hostPort: 9090
          name: metrics
          protocol: TCP
        resources:
          limits:
            cpu: 100m
            memory: 256Mi
          requests:
            cpu: 100m
            memory: 256Mi
        securityContext:
          readOnlyRootFilesystem: true
          allowPrivilegeEscalation: false
          privileged: false
          capabilities:
            drop:
              - NET_RAW
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /var/log/auditlog
          name: ti-auditlog
        - mountPath: /etc/podinfo
          name: podinfo
          readOnly: true
      initContainers:
      - name: init
        image: 385595570414.dkr.ecr.us-west-2.amazonaws.com/third-party/busybox:1.34.1
        imagePullPolicy: IfNotPresent
        command:
        - sh
        - -c
        - sysctl
        - -w
        - net.ipv4.tcp_keepalive_intvl=75
        - net.ipv4.tcp_keepalive_time=300
        securityContext:
          privileged: true
      tolerations:
      - effect: NoExecute
        key: node.kubernetes.io/not-ready
        operator: Exists
        tolerationSeconds: 300
      - effect: NoExecute
        key: node.kubernetes.io/unreachable
        operator: Exists
        tolerationSeconds: 300
      dnsPolicy: ClusterFirstWithHostNet
      hostNetwork: true
      volumes:
      - name: ti-auditlog
        emptyDir: {}
      - configMap:
          defaultMode: 420
          name: db-3a219eb3-diagnose-tidb
        name: ti-config
      - name: ti-tidb-sql-tls
        secret:
          defaultMode: 420
          secretName: db-3a219eb3-diagnose-tidb-server-secret
      - name: ti-tls
        secret:
          defaultMode: 420
          secretName: db-3a219eb3-diagnose-tidb-cluster-secret
      - downwardAPI:
          defaultMode: 420
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.annotations['tidb.auditlog.config']
            path: audit-config.yaml
        name: podinfo
      - name: tmp-volume
        emptyDir: {}
`, yamlStr)
}

func Test_RenderTiDBDiagnoseConfigMap(t *testing.T) {
	tl := initTiDBDiagnoseTemplate(t)
	yamlStr, err := tl.Render("tidb_diagnosis_configmap", tidbDiagnosisTestTemplArgs)
	require.NoError(t, err)
	require.NotEmpty(t, yamlStr)
	assert.YAMLEq(t, `apiVersion: v1
kind: ConfigMap
metadata:
  name: db-3a219eb3-diagnose-tidb
  namespace: tidb1233438346465886
  labels:
    pingcap.com/group: db-3a219eb3-diagnose-tidb
    pingcap.com/component: diagnose-tidb
    pingcap.com/cluster: db
    tags.tidbcloud.com/shared-pool: '1233438346465886'
data:
  config.toml: |
    advertise-address = 'db-3a219eb3-diagnose-tidb.db-3a219eb3-diagnose-tidb-peer.tidb1233438346465886.svc'
    disaggregated-tiflash = true
    enable-telemetry = false
    graceful-wait-before-shutdown = 15
    host = '::'
    keyspace-name = ''
    path = 'db-3a219eb3-pd.tidb1233438346465886:2379'
    store = 'tikv'
    tikv-worker-url = 'https://db-3a219eb3-tikv-worker-peer.tidb1233438346465886.svc:19000'
    [log]
    slow-query-file = '/var/log/auditlog/slowlog'

    [log.file]
    max-backups = 3

    [performance]
    tcp-keep-alive = true

    [security]
    cluster-ssl-ca = '/var/lib/tidb-tls/ca.crt'
    cluster-ssl-cert = '/var/lib/tidb-tls/tls.crt'
    cluster-ssl-key = '/var/lib/tidb-tls/tls.key'
    ssl-ca = '/var/lib/tidb-sql-tls/ca.crt'
    ssl-cert = '/var/lib/tidb-sql-tls/tls.crt'
    ssl-key = '/var/lib/tidb-sql-tls/tls.key'
    cluster-verify-cn = ['59accb4c']
    enable-sem = true
    skip-grant-table = false

    [status]
    record-db-label = true

    [tikv-client]
    [tikv-client.copr-cache]
    capacity-mb = 0.0

    [instance]
    tidb_enable_stats_owner = false
    tidb_enable_ddl = false

    [standby]
    standby-mode = true
`, yamlStr)
}

func Test_RenderTiDBDiagnoseConfigMap_WithoutTiKVWorkerURL(t *testing.T) {
	tl := initTiDBDiagnoseTemplate(t)
	templArgs := map[string]string{}
	for k, v := range tidbDiagnosisTestTemplArgs {
		templArgs[k] = v
	}
	delete(templArgs, "TiKVWorkerURL")

	yamlStr, err := tl.Render("tidb_diagnosis_configmap", templArgs)
	require.NoError(t, err)
	require.NotEmpty(t, yamlStr)
	assert.NotContains(t, yamlStr, "tikv-worker-url")
}

func Test_RenderTiDBDiagnoseSVC(t *testing.T) {
	tl := initTiDBDiagnoseTemplate(t)
	yamlStr, err := tl.Render("tidb_diagnosis_svc", tidbDiagnosisTestTemplArgs)
	require.NoError(t, err)
	require.NotEmpty(t, yamlStr)
	assert.YAMLEq(t, `apiVersion: v1
kind: Service
metadata:
  name: db-3a219eb3-diagnose-tidb
  namespace: tidb1233438346465886
spec:
  type: ClusterIP
  selector:
    pingcap.com/group: db-3a219eb3-diagnose-tidb
    pingcap.com/component: diagnose-tidb
    pingcap.com/cluster: db
  ports:
  - name: mysql-client
    port: 4000
    protocol: TCP
    targetPort: mysql-client
  - name: status
    port: 10080
    protocol: TCP
    targetPort: status
`, yamlStr)
}

func initTiDBDiagnoseTemplate(t *testing.T) *render.TemplateLibrary {
	t.Helper()
	tplPath := "../../../deployments/templates"
	templateLib := render.NewTemplateLibrary()

	for _, tpl := range tidbDiagnosisTemplates {
		data, err := os.ReadFile(filepath.Join(tplPath, tpl+".templ"))
		require.NoError(t, err, "Failed to read template file: %s", tplPath)
		templateLib.SafeNewTemplate(tpl, string(data))
	}
	return templateLib
}
