package workspace

import (
	"errors"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/google/uuid"
)

// 输入校验正则。改动需要同步更新 spec §3.6 与 dto.go 的错误消息。
var (
	slugRe   = regexp.MustCompile(`^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$`)
	branchRe = regexp.MustCompile(`^[A-Za-z0-9._/-]{1,200}$`)
)

// ValidateSlug 报告 slug 是否合法。
func ValidateSlug(slug string) error {
	if !slugRe.MatchString(slug) {
		return errors.New("slug must be lowercase alnum + '-' (1..32 chars), no leading/trailing dash")
	}
	return nil
}

// ValidateBranch 报告 branch 名是否合法（防止被 git 当成 flag）。
func ValidateBranch(b string) error {
	if !branchRe.MatchString(b) {
		return errors.New("branch must match [A-Za-z0-9._/-]{1,200}")
	}
	if strings.HasPrefix(b, "-") || strings.HasPrefix(b, "+") || strings.HasPrefix(b, "/") {
		return errors.New("branch must not start with '-', '+', or '/'")
	}
	if strings.Contains(b, "..") {
		return errors.New("branch must not contain '..'")
	}
	return nil
}

// ValidateRemoteURL 检查 scheme 白名单，并拒绝 scheme:// 形式中内嵌的 userinfo（凭据）。
func ValidateRemoteURL(u string) error {
	switch {
	case strings.HasPrefix(u, "https://"),
		strings.HasPrefix(u, "http://"),
		strings.HasPrefix(u, "ssh://"):
		// 拒绝 scheme://user:pass@host 形式的内嵌凭据：内嵌凭据会绕过本系统凭据
		// 存储并短路数据库 PAT。注意 ssh://git@host 这类裸用户名（无 ":" 密码）是
		// 合法 SSH 形式，仅当 userinfo 中带 ":" 密码时才判定为内嵌凭据。
		rest := u[strings.Index(u, "://")+len("://"):]
		authority := rest
		if i := strings.IndexByte(rest, '/'); i >= 0 {
			authority = rest[:i]
		}
		if at := strings.IndexByte(authority, '@'); at >= 0 {
			if strings.ContainsRune(authority[:at], ':') {
				return errors.New("git_remote_url must not contain embedded credentials")
			}
		}
		return nil
	case strings.HasPrefix(u, "git@"):
		return nil
	}
	return errors.New("git_remote_url must be https/http/ssh/git@ scheme")
}

// MainPath 计算 workspace.main_path 绝对路径。dataDir 是配置中的 ${DATA_DIR}。
func MainPath(dataDir string, wsID uuid.UUID) string {
	return filepath.Join(dataDir, "workspaces", wsID.String(), "main")
}

// WorktreePath 计算支线 worktree 绝对路径。branch slug 化后嵌入路径。
func WorktreePath(dataDir string, wsID uuid.UUID, branch string) string {
	return filepath.Join(dataDir, "workspaces", wsID.String(), ".worktrees", branchSlug(branch))
}

// TmpDir 是 git CLI 凭据/known_hosts 临时文件根目录。启动期需清空。
func TmpDir(dataDir string) string {
	return filepath.Join(dataDir, "tmp")
}

// branchSlug 把 branch 名转成可作为目录名的字符串。
//
// 规则：把 '/' 替换为 '_'；其他非法字符保留（branchRe 已限制）。
func branchSlug(b string) string {
	return strings.ReplaceAll(b, "/", "_")
}
