package pimport

import (
	"regexp"
	"testing"

	"github.com/pingcap/tidb/pkg/util/filter"
	"github.com/stretchr/testify/suite"
)

type utilsSuite struct {
	suite.Suite
}

func TestUtilsSuite(t *testing.T) {
	suite.Run(t, new(utilsSuite))
}

func (s *utilsSuite) TestUnpackTableID() {
	testCases := []struct {
		input    string
		isErr    bool
		expected *filter.Table
	}{
		{input: "`", isErr: true},
		{input: "``", isErr: true},
		{input: "```", isErr: true},
		{input: "````", isErr: true},
		{input: "`````", isErr: true},
		{input: "``.``", isErr: true},
		{input: "`a`.``", isErr: true},
		{input: "``.`a`", isErr: true},
		{input: "`a`,`a`", isErr: true},
		{input: "`a`.`a`", isErr: false, expected: NewTable("a", "a")},
		{input: "`a`.`a``", isErr: true},
		{input: "`a`.``a`", isErr: true},
		{input: "`a``.`a`", isErr: true},
		{input: "``a`.`a`", isErr: true},
	}

	for _, tc := range testCases {
		actual, err := unpackTableID(tc.input)
		s.Require().Equal(tc.isErr, err != nil)
		if !tc.isErr {
			s.Require().Equal(tc.expected.String(), actual.String())
		}
	}
}

func (s *utilsSuite) TestGenerateObjectNamePatternRegexp() {
	wildcardsWorks := map[string][]string{
		`db1.tbl1`:                    {"db1.tbl1"},
		`db[0-9].tbl[0-9a-f][0-9a-f]`: {"db0.tblaa", "db0.tbla0"},
		`data.*`:                      {"data.blabla", "data.bla"},
		`*.backup_*`:                  {"hello.backup_2021"},
		`employees.*`:                 {"employees.1", "employees.1ajskldla"},
		`*.WorkOrder`:                 {"hello.WorkOrder"},
		`!*.Password`:                 {"!hello.Password"},
		`!employees.salaries`:         {"!employees.salaries"},
		`db.with.dots.*`:              {"db.with.dots.hello"},
		`"db.with.dots"."tbl\1"`:      {`"db.with.dots"."tbl\1"`},
		"`db.with.dots`.`tbl\\2`":     {"`db.with.dots`.`tbl\\2`"},
		`"foo""bar".` + "foo``bar``":  {`"foo""bar".` + "foo``bar``"},
		`foo\"bar.` + "foo\\`bar":     {`foo\"bar.` + "foo\\`bar"},
		`[0-9]`:                       {"0"},
		`[a-z]`:                       {"a"},
		`[a-z][0-9][a-z]`:             {"a0b"},
		`^%$`:                         {"^%$"},
		`^.$*`:                        {`^.$*`},
		`hello`:                       {`hello`},
		`hello.`:                      {`hello.`},
		`hello*`:                      {`hello.*`, `helloabcdksdk`},
		`hello?`:                      {`hello.`, `helloa`, `hello?`},
		`hello=world\\`:               {`hello=world\\`},
		`*hello=123?`:                 {`blabalhello=123a`},
		`*hello=123/*/abc?`:           {`*hello=123/ablablabl/abcd`},
		`*station=402260*`:            {`s3://wjktest123/mydata3/data/station=402260/part-r-00000-ddaee723-f3f6-4f25-a34b-3312172aa6d7.snappy.parquet`},
		`*station=402260*.parquet`:    {`s3://wjktest123/mydata3/data/station=402260/part-r-00000-ddaee723-f3f6-4f25-a34b-3312172aa6d7.snappy.parquet`},
		`*.parquet`:                   {`s3://wjktest123/mydata3/data/station=402265/part-r-00283-ddaee723-f3f6-4f25-a34b-3312172aa6d7.snappy.parquet`, `s3://wjktest123/mydata3/data/station=402260/part-r-00001-ddaee723-f3f6-4f25-a34b-3312172aa6d7.snappy.parquet`},
	}

	for k, vs := range wildcardsWorks {
		for _, v := range vs {
			generatedRegexp := GenerateObjectNamePatternRegexp(k)
			r, err := regexp.Compile(generatedRegexp)
			s.Assert().Nil(err)
			s.Assert().True(r.MatchString(v))
		}
	}

	wildcardsNotWorks := map[string][]string{
		"hello":      {"helloa", "hellob", "chello"},
		"hello[0-9]": {"helloa", "bhello"},
		"*hello":     {"ahellob", "hello*"},
		"hello?":     {"helloa.", "bhello"},
		"^%$":        {"^%$ww"},
		"^.$*":       {"?^*$*"},
	}
	for k, vs := range wildcardsNotWorks {
		for _, v := range vs {
			generatedRegexp := GenerateObjectNamePatternRegexp(k)
			r, err := regexp.Compile(generatedRegexp)
			s.Assert().Nil(err)
			s.Assert().False(r.MatchString(v))
		}
	}
}

func (s *utilsSuite) TestParseTargetTable() {
	var (
		dbName    string
		tableName string
		err       error
	)

	type Resp struct {
		DBName    string
		TableName string
		ErrIsNil  bool
	}

	mapper := map[string]Resp{
		"mydb.mytable":                     {"mydb", "mytable", true},
		"`mydb.with.point`.`mytable.name`": {"`mydb.with.point`", "`mytable.name`", true},
		"abcd":                             {"", "", false},
		"sadlks*&*()":                      {"", "", false},
		"abcd.efg.hjks":                    {"abcd.efg", "hjks", true},
	}

	for k, v := range mapper {
		dbName, tableName, err = ParseTargetTable(k)

		if v.ErrIsNil {
			s.Assert().Nil(err)
		} else {
			s.Assert().NotNil(err)
		}

		s.Assert().Equal(v.DBName, dbName)
		s.Assert().Equal(v.TableName, tableName)
	}
}
