//go:build logs
// +build logs

package logscheck

import (
	"context"
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/observability/pkg/common/message"
	"github.com/tidbcloud/observability/pkg/common/structs"
	"github.com/tidbcloud/observability/test/ft/common/checker"
	"github.com/tidbcloud/observability/test/ft/common/checker/utils"
)

func TestLogs(t *testing.T) {
	deadline, ok := t.Deadline()
	if !ok {
		deadline = time.Now().Add(90 * time.Minute)
	}
	ctx, cancel := context.WithDeadline(context.Background(), deadline)
	defer cancel()

	// query all cluster
	r := utils.GetRegion()
	var clusters = make([]structs.ClusterBaseInfo, 0)
	for i, a := range r.Region {
		for _, b := range a {
			for _, biz := range r.BizType {
				queryReq := message.QueryClustersReq{
					CommonReqInfo: structs.CommonReqInfo{
						Vendor: constants.ProvidedVendor(i),
						Region: b,
					},
					BizType: biz,
				}
				clusters = append(clusters, utils.QueryCluster(queryReq).Clusters...)
			}
		}
	}
	fmt.Println("total clusters: ", len(clusters))
	fmt.Println("start logs check")
	defer fmt.Println("end logs check")
	i := 0
	var noLogCluster []NoDataCluster
	for _, cluster := range clusters {
		fmt.Println("------------------", i)
		i++

		// get cluster detail
		clusterDetail := utils.GetClusterDetail(message.DetailClusterReq{
			CommonReqInfo: structs.CommonReqInfo{
				Vendor: cluster.Vendor,
				Region: cluster.Region,
			},
			ID: cluster.ID,
		})

		fmt.Println(cluster.Region, cluster.Vendor, "clusterID:", cluster.ID, "tenantID:", cluster.TenantID, "applicationID:", cluster.ApplicationID, "bizType: ", cluster.BizType)
		if clusterDetail == nil || clusterDetail.Status != constants.ACTIVE || clusterDetail.ApplicationID == "k8s-infra" || clusterDetail.ApplicationID == "dataapp" {
			if clusterDetail == nil {
				fmt.Println("cluster detail is nil")
			} else {
				fmt.Printf("cluster status: %s, application id : %s\n", clusterDetail.Status, clusterDetail.ApplicationID)
			}
			continue
		}
		tidbCluster := utils.GetTiDBCluster(cluster)
		tidbStatus, createTime := utils.GetTidbClusterStatus(tidbCluster, cluster.TenantID, cluster.ApplicationID)
		if tidbStatus != "normal" {
			fmt.Println("tidb status: ", tidbStatus)
			continue
		}
		//skip gardener cluster
		if tidbCluster.ControlPlaneArch == "gardener" {
			fmt.Println("gardener cluster id:", clusterDetail.ApplicationID)
			continue
		}
		now := time.Now().Unix()
		//we skip the cluster which is created within 30min
		if now-createTime.Unix() < 30*60 {
			continue
		}
		if clusterDetail.Status == constants.ACTIVE {
			_, err := checker.CheckAll(ctx, checker.ClusterInfo{
				Provider:  string(clusterDetail.Vendor),
				Env:       BizToEnv(cluster.BizType),
				Region:    clusterDetail.Region,
				TenantID:  clusterDetail.TenantID,
				ProjectID: clusterDetail.ProjectID,
				ClusterID: clusterDetail.ApplicationID,
				O11yID:    clusterDetail.ID,
			}, checker.TimeRange{}, false, func(dt checker.DataType) error {
				fmt.Printf("no %s found for %s\n", dt, clusterDetail.ApplicationID)
				noLogCluster = append(noLogCluster, NoDataCluster{
					BaseInfo:   clusterDetail,
					CreateTime: createTime.Unix(),
					DataType:   dt,
				})
				return nil
			})
			require.NoError(t, err)
		}
	}

	fmt.Printf("-------------Clusters case test failed: %v-------------\n", len(noLogCluster))
	des := fmt.Sprintf("O11y dial test  check result. The total number of clusters whose case not pass is: %d \n", len(noLogCluster))
	send := false
	finalCluster := make([]NoDataCluster, 0)
	for j, c := range noLogCluster {
		info := fmt.Sprintf("region: %s, o11yClusterID: %s, tenantID: %s, projectID: %s, applicationID: %s dataType: %s ", c.BaseInfo.Region, c.BaseInfo.ID, c.BaseInfo.TenantID, c.BaseInfo.ProjectID, c.BaseInfo.ApplicationID, c.DataType)
		fmt.Println(info)
		if strings.HasPrefix(c.BaseInfo.BizType, "staging") {
			continue
		}
		finalCluster = append(finalCluster, c)
		send = true
		info = fmt.Sprintf("region: %s, o11yClusterID: %s, tenantID: %s, projectID: %s, applicationID: %s, dataType: %s", c.BaseInfo.Region, c.BaseInfo.ID, c.BaseInfo.TenantID, c.BaseInfo.ProjectID, c.BaseInfo.ApplicationID, c.DataType)
		des += fmt.Sprintf("No.%d ", j)
		des += info
		des += "\n\n"
		// _, err := checker.CheckAll(ctx, checker.ClusterInfo{
		// 	Provider:  string(c.BaseInfo.Vendor),
		// 	Env:       "prod",
		// 	Region:    c.BaseInfo.Region,
		// 	TenantID:  c.BaseInfo.TenantID,
		// 	ProjectID: c.BaseInfo.ProjectID,
		// 	ClusterID: c.BaseInfo.ApplicationID,
		// }, checker.TimeRange{}, func(dt checker.DataType) error {
		// 	finalCluster = append(finalCluster, c)
		// 	send = true
		// 	info = fmt.Sprintf("region: %s, o11yClusterID: %s, tenantID: %s, projectID: %s, applicationID: %s, dataType: %s", c.BaseInfo.Region, c.BaseInfo.ID, c.BaseInfo.TenantID, c.BaseInfo.ProjectID, c.BaseInfo.ApplicationID, dt)
		// 	des += fmt.Sprintf("No.%d ", j)
		// 	des += info
		// 	des += "\n\n"
		// 	return nil
		// })
		// require.NoError(t, err)
	}

	if len(finalCluster) > 0 && send == true {
		fmt.Println("post alert to jira")
		_, err := utils.PostToJira(des)
		if err != nil {
			fmt.Println(err)
		}
	}
}

type NoDataCluster struct {
	BaseInfo        *structs.ObservabilityCluster
	LastCheckedTime int64
	CreateTime      int64
	DataType        checker.DataType
}

func BizToEnv(biz string) string {
	if strings.HasPrefix(biz, "staging") {
		return "staging"
	}
	return "prod"
}
