package analyzer_test

import (
	"go/build"
	"testing"

	"github.com/pingcap-inc/alioth/extractor/go/analyzer"
	"github.com/pingcap-inc/alioth/extractor/go/compiler"
	logextractor "github.com/pingcap-inc/alioth/extractor/go/log"
	logpattern_go_proto "github.com/pingcap-inc/alioth/proto"
	. "github.com/pingcap/check"
)

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

var _ = Suite(&testCodeAnalyzerSuite{})

type testCodeAnalyzerSuite struct {
}

func (t *testCodeAnalyzerSuite) TestPackageCompile(c *C) {
	pc := compiler.NewPackageComplier(build.Default)
	testPackageImportPath := "../../../test/ast_test/example"
	pl, err := pc.Compile(testPackageImportPath)
	c.Assert(err, IsNil)
	c.Assert(pl, NotNil)

	var helper *analyzer.AstHelper
	var file *compiler.FileCompilation

	pl.ForEach(func(f *compiler.FileCompilation, h *analyzer.AstHelper) {
		file = f
		helper = h
	})

	filter := logextractor.NewFilter(nil)

	ai := analyzer.NewAstAnalyzer(filter.Filter)
	ch := ai.SetupOutput()
	file.RunAnalysis(ai, helper)
	ai.MarkDone()

	patterns := testGenerateLogPattern()
	index := 0

	for {
		pattern, ok := <-ch
		if !ok {
			break
		}

		c.Assert(pattern, DeepEquals, patterns[index])
		index++
	}
}

func testGenerateLogPattern() []*logpattern_go_proto.LogPattern {
	filePath := "test/ast_test/example/print.go"
	logPrint := &logpattern_go_proto.FuncInfo{
		Name: "LogPrint",
		Pos: &logpattern_go_proto.Position{
			FilePath: filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   10,
				Column: 1,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   31,
				Column: 2,
			},
		},
	}

	logPrint1 := &logpattern_go_proto.FuncInfo{
		Name: "logPrint1",
		Pos: &logpattern_go_proto.Position{
			FilePath: filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   33,
				Column: 1,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   42,
				Column: 2,
			},
		},
	}

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

	pattern1 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   13,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   14,
				Column: 31,
			},
		},
		Func:      logPrint,
		Level:     "info",
		Signature: []string{"\"sprint %d\""},
	}

	pattern2 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   15,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   16,
				Column: 18,
			},
		},
		Func:      logPrint,
		Level:     "info",
		Signature: []string{"\"path variable\""},
	}

	pattern3 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   17,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   18,
				Column: 16,
			},
		},
		Func:      logPrint,
		Level:     "error",
		Signature: []string{"\"test error\""},
	}

	pattern4 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   20,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   21,
				Column: 110,
			},
		},
		Func:  logPrint,
		Level: "info",
	}

	pattern5 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   27,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   28,
				Column: 23,
			},
		},
		Func:      logPrint,
		Level:     "debug",
		Signature: []string{"\"start new request\""},
	}

	pattern6 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   34,
				Column: 8,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   35,
				Column: 12,
			},
		},
		Func:       logPrint1,
		Level:      "info",
		Signature:  []string{"\"hahaha\""},
		IsDeferLog: true,
	}

	pattern7 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   36,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   37,
				Column: 36,
			},
		},
		Func:      logPrint1,
		Level:     "info",
		Signature: []string{"\"the capture routine has exited\""},
	}

	pattern8 := &logpattern_go_proto.LogPattern{
		Pos: &logpattern_go_proto.Position{
			PackageInfo: pkgPath,
			FilePath:    filePath,
			Pos: &logpattern_go_proto.CodePosition{
				Line:   39,
				Column: 2,
			},
			EndPos: &logpattern_go_proto.CodePosition{
				Line:   39,
				Column: 40,
			},
		},
		Func:  logPrint1,
		Level: "info",
	}

	return []*logpattern_go_proto.LogPattern{pattern1, pattern2, pattern3, pattern4, pattern5, pattern6, pattern7, pattern8}
}
