package recorder

import (
	"context"
	"io/ioutil"
	"os"
	"testing"

	"github.com/pingcap-inc/alioth/pkg/util"
	logpattern_go_proto "github.com/pingcap-inc/alioth/proto"
	"github.com/pingcap-inc/alioth/storage"
	. "github.com/pingcap/check"
)

func TestClient(t *testing.T) {
	TestingT(t)
}

var _ = Suite(&testUnknownSuite{})

type testUnknownSuite struct {
}

func (t *testUnknownSuite) TestUnknown(c *C) {
	tmpdir, err := ioutil.TempDir("./", "logpattern_test")
	c.Assert(err, IsNil)
	defer os.RemoveAll(tmpdir)

	store, err := storage.NewStore(tmpdir)
	c.Assert(err, IsNil)

	unknown := NewUnknowLogRecorder(store)
	exptectedRes := t.testRecordUnknow(c, unknown)

	c.Assert(unknown.logs, HasLen, 3)
	unknown.Forach(context.Background(), func(ctx context.Context, lg *logpattern_go_proto.UnknowLogPattern) error {
		expect := exptectedRes[util.PosToStr(lg.Pos)]
		c.Assert(lg, DeepEquals, expect)
		return nil
	})

	c.Assert(unknown.Flush(context.Background()), IsNil)

	unknown2 := NewUnknowLogRecorder(store)
	err = unknown2.LoadUnknowLogs(context.Background())
	c.Assert(err, IsNil)
	c.Assert(unknown2.logs, HasLen, 3)
	unknown2.Forach(context.Background(), func(ctx context.Context, lg *logpattern_go_proto.UnknowLogPattern) error {
		expect := exptectedRes[util.PosToStr(lg.Pos)]
		c.Assert(lg, DeepEquals, expect)
		unknown.Merge(context.Background(), lg)
		return nil
	})
	c.Assert(unknown.Flush(context.Background()), IsNil)

	c.Assert(unknown.logs, HasLen, 3)
	unknown.Forach(context.Background(), func(ctx context.Context, lg *logpattern_go_proto.UnknowLogPattern) error {
		expect := exptectedRes[util.PosToStr(lg.Pos)]
		c.Assert(lg, DeepEquals, expect)
		return nil
	})

	err = unknown2.LoadUnknowLogs(context.Background())
	c.Assert(err, IsNil)
	c.Assert(unknown2.logs, HasLen, 3)
	unknown2.Forach(context.Background(), func(ctx context.Context, lg *logpattern_go_proto.UnknowLogPattern) error {
		expect := exptectedRes[util.PosToStr(lg.Pos)]
		c.Assert(lg, DeepEquals, expect)
		return nil
	})
}

func (t *testUnknownSuite) testRecordUnknow(c *C, unknown *UnknowLogRecord) map[string]*logpattern_go_proto.UnknowLogPattern {
	logs := make(map[string]*logpattern_go_proto.UnknowLogPattern)

	unknownLog1 := &logpattern_go_proto.UnknowLogPattern{
		Pos: &logpattern_go_proto.Position{
			FilePath: "task.go",
			Pos: &logpattern_go_proto.CodePosition{
				Line: 138,
			},
		},
		Message:  "test log",
		Level:    "warn",
		CovCount: 2,
		CovCountByLog: map[string]int32{
			"./dm_worker1.log": 1,
			"./dm_worker2.log": 1,
		},
	}
	unknown.Record("./dm_worker1.log", "task.go", 138, "test log", "warn")
	unknown.Record("./dm_worker2.log", "task.go", 138, "test log", "error")
	logs[util.PosToStr(unknownLog1.Pos)] = unknownLog1

	unknownLog2 := &logpattern_go_proto.UnknowLogPattern{
		Pos: &logpattern_go_proto.Position{
			FilePath: "task.go",
			Pos: &logpattern_go_proto.CodePosition{
				Line: 139,
			},
		},
		Message:  "test log",
		Level:    "error",
		CovCount: 1,
		CovCountByLog: map[string]int32{
			"./dm_worker1.log": 1,
		},
	}
	unknown.Record("./dm_worker1.log", "task.go", 139, "test log", "error")
	logs[util.PosToStr(unknownLog2.Pos)] = unknownLog2

	unknownLog3 := &logpattern_go_proto.UnknowLogPattern{
		Pos: &logpattern_go_proto.Position{
			FilePath: "task.go",
			Pos: &logpattern_go_proto.CodePosition{
				Line: 140,
			},
		},
		Message:  "test log",
		Level:    "error",
		CovCount: 1,
		CovCountByLog: map[string]int32{
			"./dm_worker3.log": 1,
		},
	}
	unknown.Record("./dm_worker3.log", "task.go", 140, "test log", "error")
	logs[util.PosToStr(unknownLog3.Pos)] = unknownLog3

	return logs
}
