package git

import (
	"encoding/base64"
	"fmt"
	"strings"
)

const (
	envBitbucketUsername = "REPO_SYNC_BITBUCKET_USERNAME"
	envBitbucketToken    = "REPO_SYNC_BITBUCKET_TOKEN"
	envImportGitUsername = "REPO_SYNC_IMPORT_GIT_USERNAME"
	envImportGitPassword = "REPO_SYNC_IMPORT_GIT_PASSWORD"
)

// BasicAuthHeader returns an HTTP Authorization header value for git HTTP operations.
func BasicAuthHeader(username, token string) string {
	credentials := username + ":" + token
	encoded := base64.StdEncoding.EncodeToString([]byte(credentials))
	return "Authorization: Basic " + encoded
}

// BitbucketCredentialAuth returns git -c args and env entries for Bitbucket HTTP auth.
// http.extraHeader is unreliable for clone/fetch when the header value contains spaces.
func BitbucketCredentialAuth(username, token string) (gitArgs, env []string) {
	if username == "" || token == "" {
		return nil, nil
	}
	helper := fmt.Sprintf(
		"!f() { echo username=$%s; echo password=$%s; }; f",
		envBitbucketUsername,
		envBitbucketToken,
	)
	gitArgs = []string{
		"-c", "credential.helper=",
		"-c", "credential.helper=" + helper,
	}
	env = []string{
		envBitbucketUsername + "=" + username,
		envBitbucketToken + "=" + token,
		"GIT_TERMINAL_PROMPT=0",
	}
	return gitArgs, env
}

// CredentialAuth returns git -c args and env entries for arbitrary HTTP git credentials.
func CredentialAuth(username, password string) (gitArgs, env []string) {
	if username == "" || password == "" {
		return nil, nil
	}
	helper := fmt.Sprintf(
		"!f() { echo username=$%s; echo password=$%s; }; f",
		envImportGitUsername,
		envImportGitPassword,
	)
	gitArgs = []string{
		"-c", "credential.helper=",
		"-c", "credential.helper=" + helper,
	}
	env = []string{
		envImportGitUsername + "=" + username,
		envImportGitPassword + "=" + password,
		"GIT_TERMINAL_PROMPT=0",
	}
	return gitArgs, env
}

// RedactSecrets replaces sensitive substrings in command output before logging.
func RedactSecrets(text, username, token string) string {
	if text == "" {
		return text
	}
	out := text
	if token != "" {
		out = strings.ReplaceAll(out, token, "***")
	}
	if username != "" {
		out = strings.ReplaceAll(out, username, "***")
	}
	encoded := base64.StdEncoding.EncodeToString([]byte(username + ":" + token))
	out = strings.ReplaceAll(out, encoded, "***")
	return out
}

// ValidateRepoID checks repo_id format: {project_key}/{repo_slug}.
func ValidateRepoID(repoID string) error {
	repoID = strings.TrimSpace(repoID)
	if repoID == "" {
		return fmt.Errorf("repo_id is required")
	}
	if strings.Contains(repoID, "..") || strings.Contains(repoID, `\`) {
		return fmt.Errorf("invalid repo_id: %q", repoID)
	}
	if strings.HasPrefix(repoID, "/") {
		return fmt.Errorf("invalid repo_id: %q", repoID)
	}
	parts := strings.Split(repoID, "/")
	if len(parts) != 2 {
		return fmt.Errorf("repo_id must be project/slug, got %q", repoID)
	}
	for _, part := range parts {
		if strings.TrimSpace(part) == "" {
			return fmt.Errorf("invalid repo_id: %q", repoID)
		}
	}
	return nil
}
