package serverlessdb_operator

import (
	"time"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	. "gitcode.com/openFuyao/e2e-auto-test/e2e/serverlessdb-operator/utils"
)

var _ = Describe("ServerlessDB 资源不足场景",
	Label("serverlessdb-operator", "with-workload-cluster", "26.01"), Label("P0"), func() {

		It("serverlessdb-IT-021:资源不足时 Pod 创建后处于 Pending 状态,Operator 正常处理", func() {
			poolName := "pool-ins001"

			By("创建资源需求极高的资源池(超出节点容量)")
			pool := BuildDBResourcePoolWithResources(poolName, testNs, 2, pgVersion,
				"100", "500Gi", "100", "500Gi")
			_, err := CreatePool(ctx, k8sClient, pool)
			Expect(err).NotTo(HaveOccurred(), "创建高资源需求资源池应当成功")

			DeferCleanup(func() {
				_ = DeletePool(ctx, k8sClient, testNs, poolName)
			})

			By("等待 Pod 被创建")
			Eventually(func() int {
				pods, err := k8sClient.ListPods(ctx, testNs, metav1.ListOptions{
					LabelSelector: LabelEq(LabelDBPool, poolName),
				})
				if err != nil {
					return 0
				}
				return len(pods.Items)
			}, reconcileWait, reconcilePoll).Should(BeNumerically(">=", 1), "应当创建至少一个 Pod")

			By("验证 Pod 处于 Pending 状态(无法调度)")
			Consistently(func(g Gomega) {
				pods, err := k8sClient.ListPods(ctx, testNs, metav1.ListOptions{
					LabelSelector: LabelEq(LabelDBPool, poolName),
				})
				g.Expect(err).NotTo(HaveOccurred())

				for _, pod := range pods.Items {
					g.Expect(pod.Status.Phase).To(Equal(corev1.PodPending),
						"Pod %s 应当处于 Pending 状态", pod.Name)
					var hasUnschedulableCondition bool
					for _, cond := range pod.Status.Conditions {
						if cond.Type == corev1.PodScheduled && cond.Status == corev1.ConditionFalse && cond.Reason == "Unschedulable" {
							hasUnschedulableCondition = true
							break
						}
					}
					g.Expect(hasUnschedulableCondition).To(BeTrue(),
						"Pod %s 应当有不可调度条件", pod.Name)
				}
			}, 90*time.Second, 10*time.Second).Should(Succeed(),
				"Pod 应当持续保持 Pending 状态")

			By("验证 Operator 没有崩溃")
			Eventually(func(g Gomega) {
				_, err := GetPool(ctx, k8sClient, testNs, poolName)
				g.Expect(err).NotTo(HaveOccurred(), "资源池应当存在")
			}, 30*time.Second, 5*time.Second).Should(Succeed(), "Operator 应当正常响应")
		})

		It("serverlessdb-IT-022:资源不足扩容时 Pod 处于 resize pending/in-progress 状态,Operator 正常处理", func() {
			poolName := "pool-ins002"

			By("创建正常资源需求的资源池")
			createPoolAndAwaitWarm(poolName, 1)

			By("申请实例")
			appRef := "app-ins002"
			resp := allocateAndAwaitRunning(appRef)
			Expect(resp).NotTo(BeNil(), "申请实例应当返回响应")

			By("发起超出节点容量的扩容请求")
			_, status, err := apiClient.Resize(ctx, testNs, appRef, &ResizeInstanceRequest{
				Containers: []ContainerResource{{
					Name: ContainerCompute,
					Resources: InstanceResources{
						Cpu: "100", Memory: "500Gi",
						CpuLimit: "100", MemoryLimit: "500Gi",
					},
				}},
			})
			Expect(err).NotTo(HaveOccurred(), "扩容请求应当成功")
			Expect(status).To(Equal(200), "扩容请求应当返回 200")

			By("验证扩容请求被 Operator 接受")
			Eventually(func(g Gomega) string {
				return DBInstancePhase(dbInstanceByAppRef(appRef))
			}, 15*time.Second, 2*time.Second).Should(Or(Equal("Scaling"), Equal("Running")),
				"实例应当进入 Scaling 或保持 Running 状态")

			By("验证 Pod 存活且 Operator 正常运行")
			Eventually(func(g Gomega) {
				pods, err := k8sClient.ListPods(ctx, testNs, metav1.ListOptions{
					LabelSelector: LabelEq(LabelAppRef, appRef),
				})
				g.Expect(err).NotTo(HaveOccurred())
				g.Expect(pods.Items).NotTo(BeEmpty(), "Pod 应当存在")
				g.Expect(pods.Items[0].Status.Phase).To(Equal(corev1.PodRunning), "Pod 应当保持 Running")

				pool, err := GetPool(ctx, k8sClient, testNs, poolName)
				g.Expect(err).NotTo(HaveOccurred(), "资源池应当存在,Operator 正常响应")
				g.Expect(pool.GetDeletionTimestamp().IsZero()).To(BeTrue(), "资源池不应处于删除状态")
			}, 30*time.Second, 5*time.Second).Should(Succeed(),
				"Pod 应当存活且 Operator 正常响应")
		})
	})