package github

import (
	"encoding/base64"
	"regexp"
	"slices"

	"github.com/google/go-github/v50/github"
	"github.com/pingcap/errors"
	"gopkg.in/yaml.v3"
)

const Path = "tidbcloud.yml"

var validModes = []string{ModeReset, ModeReserve}

type Config struct {
	GitHubConfig GitHubConfig `yaml:"github"`
}

type GitHubConfig struct {
	BranchConfig BranchConfig `yaml:"branch"`
}

type BranchConfig struct {
	// blockList for branch name with higher priority than allowList.
	BlockList []string `yaml:"blockList"`
	// allowList for branch name.
	AllowList []string `yaml:"allowList"`
	// whether destroy branch after pr closed.
	AutoDestroy bool `yaml:"autoDestroy"`
	// set the mode of how the app handles the previous commit.
	Mode string `yaml:"mode"`
}

func GetDefaultConfig() *Config {
	var DefaultConfig = &Config{
		GitHubConfig: GitHubConfig{
			BranchConfig: BranchConfig{
				BlockList:   nil,
				AllowList:   nil,
				AutoDestroy: true,
				Mode:        ModeReset,
			},
		},
	}
	return DefaultConfig
}

func UnmarshallGitConfig(contents *github.RepositoryContent) (*Config, error) {
	if contents == nil || contents.Content == nil {
		return nil, errors.New("contents is empty")
	}
	decodeContent, err := base64.StdEncoding.DecodeString(*contents.Content)
	if err != nil {
		return nil, err
	}
	var config = GetDefaultConfig()
	if err = yaml.Unmarshal(decodeContent, &config); err != nil {
		return nil, err
	}
	return config, nil
}

func (g *Config) CheckGitConfig() error {
	blockList := g.GitHubConfig.BranchConfig.BlockList
	allowList := g.GitHubConfig.BranchConfig.AllowList
	mode := g.GitHubConfig.BranchConfig.Mode
	for _, block := range blockList {
		if _, err := regexp.Compile(block); err != nil {
			return err
		}
	}
	for _, allow := range allowList {
		if _, err := regexp.Compile(allow); err != nil {
			return err
		}
	}
	if !slices.Contains(validModes, mode) {
		return errors.New("invalid mode")
	}
	return nil
}

func (g *Config) MatchBranch(branchName string) (bool, error) {
	blockList := g.GitHubConfig.BranchConfig.BlockList
	allowList := g.GitHubConfig.BranchConfig.AllowList

	// match any blockList will return false
	for _, block := range blockList {
		match, err := regexp.MatchString(block, branchName)
		if err != nil {
			return true, err
		}
		if match {
			return false, nil
		}
	}

	// allowList default value is .*
	if len(allowList) == 0 {
		allowList = append(allowList, ".*")
	}

	for _, allow := range allowList {
		match, err := regexp.MatchString(allow, branchName)
		if err != nil {
			return false, err
		}
		if match {
			return true, nil
		}
	}
	return false, nil
}
