package recorder

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

	"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"
)

var _ = Suite(&testPatternSuite{})

type testPatternSuite struct {
}

func (t *testPatternSuite) TestPattern(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)

	ps := NewLogPattern(store)
	exptectedRes := t.testRecordPattern(c, ps)

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

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

	ps2 := NewLogPattern(store)
	err = ps2.LoadPattern(context.Background())
	c.Assert(err, IsNil)
	c.Assert(ps2.logs, HasLen, 3)
	ps2.Forach(context.Background(), func(ctx context.Context, lg *logpattern_go_proto.LogPattern) error {
		expect := exptectedRes[util.PosToStr(lg.Pos)]
		c.Assert(lg, DeepEquals, expect)
		ps.Record(lg)
		return nil
	})
	c.Assert(ps.Flush(context.Background()), IsNil)

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

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

func (t *testPatternSuite) testRecordPattern(c *C, ps *LogPattern) map[string]*logpattern_go_proto.LogPattern {
	logs := make(map[string]*logpattern_go_proto.LogPattern)

	fun := &logpattern_go_proto.FuncInfo{
		Pos: &logpattern_go_proto.Position{
			FilePath: "task.go",
			Pos: &logpattern_go_proto.CodePosition{
				Line:   110,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   200,
				Column: 20,
			},
		},
		Name: "test",
	}

	pkgPath := &logpattern_go_proto.Package{
		Repo: "github.com/pingcap/pingcap-inc/alioth",
		Path: "recorder",
	}

	pattern1 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			FilePath: "task.go",
			Pos: &logpattern_go_proto.CodePosition{
				Line:   138,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   138,
				Column: 20,
			},
			PackageInfo: pkgPath,
		},
		Func:      fun,
		Level:     "warn",
		Signature: []string{"test log"},
	}
	ps.Record(pattern1)
	ps.Record(pattern1)
	logs[util.PosToStr(pattern1.Pos)] = pattern1

	pattern2 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			FilePath: "task.go",
			Pos: &logpattern_go_proto.CodePosition{
				Line:   139,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   140,
				Column: 20,
			},
			PackageInfo: pkgPath,
		},
		Func:      fun,
		Level:     "error",
		Signature: []string{"test log"},
	}
	ps.Record(pattern2)
	logs[util.PosToStr(pattern2.Pos)] = pattern2

	pattern3 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			FilePath: "task.go",
			Pos: &logpattern_go_proto.CodePosition{
				Line:   140,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   140,
				Column: 20,
			},
			PackageInfo: pkgPath,
		},
		Func:      fun,
		Level:     "error",
		Signature: []string{"test log"},
	}
	ps.Record(pattern3)
	logs[util.PosToStr(pattern3.Pos)] = pattern3

	return logs
}
