package importer

import (
	"archive/tar"
	"fmt"
	"os"
	"testing"

	"github.com/DataDog/zstd"
	"github.com/onsi/gomega"
	"github.com/pingcap/log"
	"go.uber.org/zap"

	"github.com/pingcap-inc/clinic/pkg/config"
	_const "github.com/pingcap-inc/clinic/pkg/const"
	"github.com/pingcap-inc/clinic/pkg/es"
	log2 "github.com/pingcap-inc/clinic/pkg/importer/log"
)

func Test_ImportLogs(t *testing.T) {
	g := gomega.NewWithT(t)

	clusterID := "6860009869741753344"
	orgID := uint(1)

	cfg := config.LogConfig{
		Endpoint: fmt.Sprintf("http://127.0.0.1:%d", es.EsPort),
		KibanaConfig: config.KibanaConfig{
			AddressConfig: config.AddressConfig{
				Host: "127.0.0.1",
				Port: es.KibanaPort,
			},
		},
		Password: "admin",
		User:     "admin",
	}

	importer := NewImporter(&ImporterOption{
		LogConfig:                cfg,
		OrgID:                    orgID,
		FileUUID:                 "8df9e3075057432-2be068847b212ee7-a71cd20639ea6108-a71cd20639ea6108",
		ClusterID:                clusterID,
		ExpectedRebuildTaskTypes: []_const.TaskType{_const.LogTask},
		DataPath:                 dataPath,
		BeginTS:                  1635000000000,
		EndTS:                    1636000000000,
	})

	needToRebuildTasks := make(map[_const.TaskType]struct{})
	for _, tt := range _const.AllTaskType() {
		needToRebuildTasks[tt] = struct{}{}
	}

	//cj, err := log2.TestClusterJSON("./testdata/cluster.json")
	//rt := &rebuildTask{
	//	orgID:       orgID,
	//	importer:    importer,
	//	clusterInfo: cluster.NewImportComponentsMeta(cj),
	//	RebuildTaskOption: &RebuildTaskOption{
	//		FileUUID:  "8df9e3075057432-2be068847b212ee7-a71cd20639ea6108-a71cd20639ea6108",
	//		ClusterID: clusterID,
	//	},
	//	needToRebuildTask: needToRebuildTasks,
	//}

	//importer := NewImporter(ImporterOption{
	//	MetricHost: "127.0.0.1",
	//	MetricPort: vmPortStart,
	//	LogConfig:  cfg,
	//})
	//importer.disableRebuildReport = true

	insertCount := 110

	// g.Expect(err).To(gomega.Succeed())

	// lt := NewLogsTask(cfg, clusterID, "", "8df9e3075057432-2be068847b212ee7-a71cd20639ea6108-a71cd20639ea6108", cluster.NewImportComponentsMeta(cj), nil)

	for i := 0; i < 5; i++ {
		path, err := newLogTar(insertCount)
		g.Expect(err).To(gomega.Succeed())
		importer.opt.localFilePath = path
		// runner, err := NewSortingTable(forkTaskExecutor[slowTask], NewSlowSortingBaggingTask(rt), rt)
		g.Expect(importer.Rebuild()).To(gomega.Succeed())
	}
	// check normal log
	r := log2.QueryESEventually(&log2.ESQueryOption{
		ClusterID:  clusterID,
		Host:       "172.16.5.137",
		Component:  "tidb",
		StartTime:  1635240046000,
		EndTime:    1635240346000,
		Level:      "info",
		InstanceID: "tidb-4000",
		OrgID:      orgID,
	}, g, insertCount)

	actualLogs := make([]string, insertCount)
	for i := 0; i < insertCount; i++ {
		actualLogs[i] = r[i].Message
	}

	for i := 0; i < insertCount; i++ {
		g.Expect(actualLogs).To(gomega.ContainElements(fmt.Sprintf("[server.go:194%d] [\"register REST path\"] [path=/pd/api/v1]", i)))
	}

	// check slow query log
	slowRecords := log2.QueryESSlowQueryLogEventually(&log2.ESQuerySlowQueryLogOption{
		ClusterID:  clusterID,
		Host:       "172.16.5.137",
		Component:  "tidb",
		StartTime:  1637204400000,
		EndTime:    1637208600000,
		InstanceID: "tidb-4000",
		OrgID:      orgID,
	}, g, 6)

	expectedPlan := []string{
		"38578c1f3993b2efb6038f9d646725285acb5b4da69ce3a680bb03a80d7e1baf",
		"fe3086933b57caadfc420fe3ff339c5c55cd557fa25b9d0e6e4cc6774f683510",
		"104f9660a4068c14140caa4f3ac2bbd9cbf4078e15183db5b455a5bec0bed730",
		"aa03ae0c8abec8ff2ed3dba6ba97d916527ab94136c2f5846d73cb03a310230b",
		"aa03ae0c8abec8ff2ed3dba6ba97d916527ab94136c2f5846d73cb03a310230b",
		"aa03ae0c8abec8ff2ed3dba6ba97d916527ab94136c2f5846d73cb03a310230b",
	}
	expectedDigestPlan := []string{
		"1a7fc9a562fe2129b4092e75f901b1aba9715c9e285f7c7fb10f02fa644fd096",
		"a5e33155313418557311d13039dbf20aa54df3b825d062bdca92f1a271e5778a",
		"294588b98252c0f39c41f73f36c4c0d9b476592d65b30373c7b69813142d89ae",
		"711670b755902dc411113b3418655c784b1e141cdbe2ef2495ffae92189d063e",
		"711670b755902dc411113b3418655c784b1e141cdbe2ef2495ffae92189d063e",
		"711670b755902dc411113b3418655c784b1e141cdbe2ef2495ffae92189d063e",
	}
	expectedTxnStartTs := []uint64{
		429183368626701409,
		429183479093919912,
		429183527472862531,
		429184253388915714,
		429184263179995015,
		429184276745688234,
	}
	expectedIsInternal := []int64{
		0,
		0,
		0,
		0,
		0,
		0,
	}

	expectedConnectionID := []uint64{
		1281,
		1309,
		1309,
		1317,
		1327,
		1335,
	}

	expectedUser := []string{
		"root",
		"root",
		"root",
		"root",
		"root",
		"root",
	}

	expectedQueryTime := []float64{
		14.712930932999999,
		6.8915668,
		5.679531035,
		1.529137651,
		1.5226775479999999,
		1.521357259,
	}

	expectParseTime := []float64{
		0.000061903,
		0.000026283,
		0.000045397,
		0,
		0,
		0,
	}

	expectedWaitTs := []float64{
		0.004978558,
		0.005013662,
		0.000533898,
		0.002886405,
		0.006092136,
		0.000009627,
	}

	expectedNumWriteSqlRespTotal := []float64{
		0.000023635,
		0.0000027,
		0.000002204,
		0.000019589,
		0.000083355,
		0.000050406,
	}

	for i, rd := range slowRecords {
		g.Expect(rd.Digest).To(gomega.Equal(expectedPlan[i]))
		g.Expect(rd.PlanDigest).To(gomega.Equal(expectedDigestPlan[i]))

		g.Expect(rd.ConnetionID).To(gomega.Equal(expectedConnectionID[i]))
		g.Expect(rd.TxnStartTs).To(gomega.Equal(expectedTxnStartTs[i]))
		g.Expect(rd.IsInternal).To(gomega.Equal(expectedIsInternal[i]))
		g.Expect(rd.User).To(gomega.Equal(expectedUser[i]))
		g.Expect(rd.QueryTime).To(gomega.Equal(expectedQueryTime[i]))

		g.Expect(rd.ParseTime).To(gomega.Equal(expectParseTime[i]))
		g.Expect(rd.WaitTs).To(gomega.Equal(expectedWaitTs[i]))
		g.Expect(rd.WriteSqlResponseTotal).To(gomega.Equal(expectedNumWriteSqlRespTotal[i]))
	}
	g.Expect(len(slowRecords)).To(gomega.Equal(6))
}

func newLogTar(insertCount int) (string, error) {
	var logs string
	for i := 0; i < insertCount; i++ {
		logs += fmt.Sprintf("[2021/10/26 17:24:06.093 +08:00] [INFO] [server.go:194%d] [\"register REST path\"] [path=/pd/api/v1]\n", i)
	}

	file, err := os.CreateTemp("", "")
	if err != nil {
		return "", err
	}
	defer func() {
		_ = file.Close()
	}()

	zstdWriter := zstd.NewWriter(file)
	defer func() {
		_ = zstdWriter.Close()
	}()

	tw := tar.NewWriter(zstdWriter)
	defer func() {
		if err := tw.Close(); err != nil {
			log.Error("close failed", zap.Error(err))
		}
	}()

	files := []string{
		"172.16.5.137/chj/app/tidb/deploy/tidb-4000/log/tidb.log",
		"172.21.58.64/chj/app/tidb/deploy/tikv-20160/log/tikv.log",
		"172.21.49.84/chj/app/tidb/deploy/tidb-4000/log/pd.log",
		"172.21.58.87/chj/app/tidb/deploy/tiflash-9000/log/tiflash.log",
	}

	fdata := []byte(logs)
	for _, f := range files {
		hdr := &tar.Header{
			Name: f,
			Mode: 0o600,
			Size: int64(len(fdata)),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			log.Error("write header failed", zap.Error(err))
			return "", err
		}
		if _, err := tw.Write(fdata); err != nil {
			log.Error("write failed", zap.Error(err))
			return "", err
		}
	}
	// write slow query log content
	slowQueryLogFile := "172.16.5.137/chj/app/tidb/deploy/tidb-4000/log/tidb_slow_query.log"
	slowQueryBuf, err := os.ReadFile("./testdata/172.16.5.137/chj/app/tidb/deploy/tidb-4000/log/tidb_slow_query.log")
	if err != nil {
		return "", err
	}
	hdr := &tar.Header{
		Name: slowQueryLogFile,
		Mode: 0o600,
		Size: int64(len(slowQueryBuf)),
	}
	if err := tw.WriteHeader(hdr); err != nil {
		log.Error("write header failed", zap.Error(err))
		return "", err
	}
	if _, err := tw.Write(slowQueryBuf); err != nil {
		log.Error("write failed", zap.Error(err))
		return "", err
	}

	return file.Name(), nil
}
