package git

import (
	"strconv"

	"github.com/tidbcloud/ecosystem-service/internal/storage/db/git"

	"github.com/pingcap/errors"
)

type ProviderType string

var (
	validGitProvider = []git.GitProvider{git.GitHub}
)

type AddConnectionRequest struct {
	GitProvider string `form:"git_provider" enums:"github" json:"git_provider" binding:"required"`
	RepoName    string `form:"repo_name" json:"repo_name" binding:"required"`
}

func (a *AddConnectionRequest) check() error {
	// check GitProvider
	if a.GitProvider == "" {
		return errors.New("Git provider is required")
	}
	if a.GitProvider != "" {
		isProviderValid := false
		for _, provider := range validGitProvider {
			if a.GitProvider == string(provider) {
				isProviderValid = true
			}
		}
		if !isProviderValid {
			return errors.New("Invalid git_provider")
		}
	}
	return nil
}

type AddConnectionResponse struct {
	ID uint64 `json:"id"`
	BaseResp
}

type ListConnectionResponse struct {
	Connections []*TiDBGitConnectionVO `json:"connections"`
	BaseResp
}

type GetConnectionResponse struct {
	Connection *TiDBGitConnectionVO `json:"connection"`
	BaseResp
}

type GetGitHubRepoRequest struct {
	InstallationID int64  `form:"installation_id" json:"installation_id" binding:"required"`
	RepoName       string `form:"repo_name" json:"repo_name"`
	Page           int    `form:"page" json:"page"`
	PerPage        int    `form:"per_page" json:"per_page"`
}

type GetGitHubRepoRequestV2 struct {
	InstallationID int64  `form:"installation_id" json:"installation_id" binding:"required"`
	RepoName       string `form:"repo_name" json:"repo_name"`
	AccessToken    string `form:"access_token" json:"access_token"`
	RefreshToken   string `form:"refresh_token" json:"refresh_token"`
	Page           int    `form:"page" json:"page"`
	PerPage        int    `form:"per_page" json:"per_page"`
}

type GetGitHubRepoResponse struct {
	Repositories []*RepositoriesVO `json:"repositories"`
	Total        int               `json:"total"`
	BaseResp
}

type GetGitHubAccountsRequest struct {
	Accounts string `form:"accounts" json:"accounts" binding:"required"`
}

type GetGitHubAccountsResponse struct {
	Accounts []*AccountsVO `json:"accounts"`
}

type ExchangeGitHubTokenRequest struct {
	Code string `form:"code" json:"code" binding:"required"`
}

type ExchangeGitHubTokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	BaseResp
}

type GetGitHubInstallAccountsRequest struct {
	AccessToken  string `form:"access_token" json:"access_token"`
	RefreshToken string `form:"refresh_token" json:"refresh_token"`
}

type GetGitHubInstallAccountsResponse struct {
	Accounts     []*AccountsVO `json:"accounts"`
	AccessToken  string        `json:"access_token"`
	RefreshToken string        `json:"refresh_token"`
	BaseResp
}

type AccountsVO struct {
	Name           string `json:"name"`
	InstallationID int64  `json:"installation_id"`
	OwnerType      string `json:"owner_type"`
}

type RepositoriesVO struct {
	ID       int64  `json:"id"`
	Name     string `json:"name"`
	FullName string `json:"full_name"`
}

type TiDBGitConnectionVO struct {
	TiDBClusterID   string `json:"tidb_cluster_id"`
	GitProvider     string `json:"git_provider"`
	RepoName        string `json:"repo_name"`
	TiDBClusterName string `json:"tidb_cluster_name"`
}

type TiDBCluster struct {
	TiDBProject
	TiDBClusterID string `json:"tidb_cluster_id" uri:"cluster_id" binding:"required"`
}

type TiDBProject struct {
	TiDBOrgID     string `json:"tidb_org_id" uri:"org_id" binding:"required"`
	TiDBProjectID string `json:"tidb_project_id" uri:"project_id" binding:"required"`
}

type BaseResp struct {
	BaseResp Resp `json:"base_resp"`
}

type Resp struct {
	ErrorCode    int64  `json:"err_code"`
	ErrorMessage string `json:"err_msg"`
}

func NewBaseResp(code int64, message string) *BaseResp {
	return &BaseResp{
		BaseResp: Resp{
			ErrorCode:    code,
			ErrorMessage: message,
		},
	}
}

func parseUintIDForTiDBCluster(path TiDBCluster) (uint64, uint64, uint64, error) {
	orgID, projectID, err := parseUintIDForTiDBProject(path.TiDBProject)
	if err != nil {
		return 0, 0, 0, errors.Trace(err)
	}

	clusterID, err := strconv.ParseUint(path.TiDBClusterID, 10, 64)
	if err != nil {
		return orgID, projectID, 0, errors.Trace(err)
	}
	return orgID, projectID, clusterID, nil
}

func parseUintIDForTiDBProject(path TiDBProject) (uint64, uint64, error) {
	orgID, err := strconv.ParseUint(path.TiDBOrgID, 10, 64)
	if err != nil {
		return 0, 0, errors.Trace(err)
	}

	projectID, err := strconv.ParseUint(path.TiDBProjectID, 10, 64)
	if err != nil {
		return orgID, 0, errors.Trace(err)
	}

	return orgID, projectID, nil
}
