package ci

import (
	"fmt"
	"strings"

	gitdomain "github.com/forgeo/forgebucket/internal/domain/git"
	"gopkg.in/yaml.v3"
)

const workflowDir = ".forgebucket/workflows"

// ListWorkflows returns the file paths of all workflow YAML files in a repo at a
// given ref. Returns nil (no error) when the workflows directory doesn't exist.
func ListWorkflows(repoPath, ref string) ([]string, error) {
	entries, err := gitdomain.TreeLS(repoPath, ref, workflowDir)
	if err != nil {
		// Directory does not exist at this ref — no workflows, not an error.
		return nil, nil
	}
	var paths []string
	for _, e := range entries {
		if e.Type == "blob" && (strings.HasSuffix(e.Name, ".yml") || strings.HasSuffix(e.Name, ".yaml")) {
			paths = append(paths, workflowDir+"/"+e.Name)
		}
	}
	return paths, nil
}

// ParseWorkflow reads and parses a single workflow YAML file from the repo at ref.
func ParseWorkflow(repoPath, ref, filePath string) (*WorkflowFile, error) {
	data, err := gitdomain.BlobCat(repoPath, ref, filePath)
	if err != nil {
		return nil, fmt.Errorf("read %s: %w", filePath, err)
	}
	var wf WorkflowFile
	if err := yaml.Unmarshal(data, &wf); err != nil {
		return nil, fmt.Errorf("parse %s: %w", filePath, err)
	}
	return &wf, nil
}

// MatchesPushTrigger reports whether a workflow should run for a push to ref.
// ref is the full ref name, e.g. "refs/heads/main".
func MatchesPushTrigger(wf *WorkflowFile, ref string) bool {
	if wf.On.Push == nil {
		return false
	}
	trigger := wf.On.Push
	// No branch filter means "all branches".
	if len(trigger.Branches) == 0 && len(trigger.Tags) == 0 {
		return true
	}
	branch := strings.TrimPrefix(ref, "refs/heads/")
	for _, pattern := range trigger.Branches {
		if matchGlob(pattern, branch) {
			return true
		}
	}
	tag := strings.TrimPrefix(ref, "refs/tags/")
	for _, pattern := range trigger.Tags {
		if matchGlob(pattern, tag) {
			return true
		}
	}
	return false
}

// matchGlob supports simple "*" wildcards (not full glob).
func matchGlob(pattern, s string) bool {
	if pattern == "*" {
		return true
	}
	if !strings.Contains(pattern, "*") {
		return pattern == s
	}
	parts := strings.SplitN(pattern, "*", 2)
	return strings.HasPrefix(s, parts[0]) && strings.HasSuffix(s, parts[1])
}
