package pimport

import (
	"net/url"
	"regexp"
	"strings"
	"unicode/utf8"

	"github.com/pingcap/errors"
	"github.com/pingcap/tidb/pkg/util/filter"
	"github.com/tidbcloud/dataflow-service/internal/utils"
)

// unpackTableID unpacks table ID to <schema, table> pair.
// an example: `db1`.`tb1` => filter.Table{Schema: "db1", Table: "tb1"}.
func unpackTableID(id string) (*filter.Table, error) {
	dbName, tableName, err := utils.UnpackFullTableName(id)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return NewTable(dbName, tableName), nil
}

func NewTable(schema, table string) *filter.Table {
	return &filter.Table{
		Schema: schema,
		Name:   table,
	}
}

var targetTableRegexp = regexp.MustCompile("^(`.+`)\\.(`.+`)|(.+)\\.(.+)$")

// todo: duplicate with generateObjectNamePatternRegexp in infra-api
func GenerateObjectNamePatternRegexp(wildcards string) string {
	// regexp syntax: https://en.wikipedia.org/wiki/Regular_expression
	var sb strings.Builder

	sb.WriteRune('^')

	cursor := 0
	maxlen := len(wildcards)

	for cursor < maxlen {
		r, sz := utf8.DecodeRuneInString(wildcards[cursor:])

		switch r {
		// defined in https://en.wikipedia.org/wiki/Glob_(programming)#Syntax
		case '{', '}', '(', ')', '^', '$', '.', '|', '+', '\\':
			sb.WriteString(`\`)
			sb.WriteRune(r)
		case '?':
			sb.WriteRune('.')
		case '*':
			sb.WriteString(".*")
		default:
			sb.WriteRune(r)
		}

		cursor += sz
	}

	sb.WriteRune('$')
	return sb.String()
}

// todo: duplicate with ParseTargetTable in infra-api
func ParseTargetTable(targetTable string) (string, string, error) {
	var result []string

	for _, i := range targetTableRegexp.FindStringSubmatch(targetTable) {
		if i != "" {
			result = append(result, i)
		}
	}

	if len(result) != 3 {
		return "", "", errors.Errorf("Target table pattern does not match the requirement, please refer the document.")
	}

	return result[1], result[2], nil
}

func EscapeQuery(rawUrl string) (string, error) {
	sourceUrl, err := url.Parse(rawUrl)
	if err != nil {
		return "", err
	} else {
		sourceUrl.RawQuery = ""
	}
	return sourceUrl.String(), nil
}
