// Copyright 2026 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build e2e

package framework

import (
	"context"
	"fmt"

	"github.com/onsi/ginkgo/v2"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"

	"github.com/tidbcloud/cluster-service-ng/internal/capacity-planner/test/e2e/waiter"
)

const (
	autoscalerCRDName     = "autoscalers.autoscaling.pingcap.com"
	metricsAPIServiceName = "v1beta1.metrics.k8s.io"
)

var (
	crdResource = schema.GroupVersionResource{
		Group: "apiextensions.k8s.io", Version: "v1", Resource: "customresourcedefinitions",
	}
	apiServiceResource = schema.GroupVersionResource{
		Group: "apiregistration.k8s.io", Version: "v1", Resource: "apiservices",
	}
	requiredTiDBOperatorCRDs = []string{
		"clusters.core.pingcap.com",
		"pdgroups.core.pingcap.com",
		"tidbgroups.core.pingcap.com",
		"tikvgroups.core.pingcap.com",
	}
)

// VerifyAdminNamespace checks the shared namespace prepared by make testdeploy.
func (f *Framework) VerifyAdminNamespace(ctx context.Context) {
	namespace := &corev1.Namespace{}
	opCtx, cancel := context.WithTimeout(ctx, apiTimeout)
	defer cancel()
	must(f.Client.Get(opCtx, types.NamespacedName{Name: f.config.adminNamespace}, namespace),
		"verify shared admin namespace %q", f.config.adminNamespace)
	fmt.Fprintf(ginkgo.GinkgoWriter, "verified shared admin namespace %s\n", f.config.adminNamespace)
}

// VerifyAutoscalerCRD checks that the local planner API is established.
func (f *Framework) VerifyAutoscalerCRD(ctx context.Context) {
	opCtx, cancel := context.WithTimeout(ctx, apiTimeout)
	defer cancel()
	must(waiter.CRDEstablished(opCtx, f.Dynamic, crdResource, autoscalerCRDName, apiTimeout),
		"verify Autoscaler CRD %q", autoscalerCRDName)
	fmt.Fprintf(ginkgo.GinkgoWriter, "verified Autoscaler CRD %s\n", autoscalerCRDName)
}

// VerifyMetricsServer checks that the aggregated metrics API is available.
func (f *Framework) VerifyMetricsServer(ctx context.Context) {
	opCtx, cancel := context.WithTimeout(ctx, apiTimeout)
	defer cancel()
	must(waiter.APIServiceAvailable(opCtx, f.Dynamic, apiServiceResource, metricsAPIServiceName),
		"verify metrics APIService %q", metricsAPIServiceName)
	fmt.Fprintf(ginkgo.GinkgoWriter, "verified metrics APIService %s is Available\n", metricsAPIServiceName)
}

// VerifyTiDBOperator checks the operator Deployment and the APIs used by the suite.
func (f *Framework) VerifyTiDBOperator(ctx context.Context) {
	opCtx, cancel := context.WithTimeout(ctx, apiTimeout)
	defer cancel()
	for _, name := range requiredTiDBOperatorCRDs {
		must(waiter.CRDEstablished(opCtx, f.Dynamic, crdResource, name, apiTimeout),
			"verify TiDB Operator CRD %q", name)
	}

	deployment := types.NamespacedName{
		Namespace: f.config.adminNamespace,
		Name:      fmt.Sprintf("tidb-operator-%s", f.config.tiDBOperatorRelease),
	}
	must(waiter.DeploymentAvailable(opCtx, f.Client, deployment),
		"verify TiDB Operator Deployment %s", deployment.String())
	fmt.Fprintf(ginkgo.GinkgoWriter, "verified TiDB Operator Deployment %s is Available\n", deployment.String())
}

// VerifyCapacityPlanner checks the Deployment installed by make deploy.
func (f *Framework) VerifyCapacityPlanner(ctx context.Context) {
	opCtx, cancel := context.WithTimeout(ctx, apiTimeout)
	defer cancel()
	deployment := types.NamespacedName{
		Namespace: f.config.capacityPlannerNamespace,
		Name:      f.config.capacityPlannerDeployment,
	}
	must(waiter.DeploymentAvailable(opCtx, f.Client, deployment),
		"verify capacity planner Deployment %s", deployment.String())
	fmt.Fprintf(ginkgo.GinkgoWriter, "verified capacity planner Deployment %s is Available\n", deployment.String())
}
