// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package workflowpattern

import (
	"strings"

	"gitea.dev/modules/glob"
)

type WorkflowPattern struct {
	negative bool
	glob     glob.Glob
}

func CompilePatterns(patterns ...string) ([]*WorkflowPattern, error) {
	ret := make([]*WorkflowPattern, 0, len(patterns))
	for _, pattern := range patterns {
		cp, err := glob.CompileWorkflow(pattern)
		if err != nil {
			return nil, err
		}
		ret = append(ret, &WorkflowPattern{glob: cp, negative: strings.HasPrefix(pattern, "!")})
	}
	return ret, nil
}

// Skip returns true if the workflow should be skipped per paths/branches semantics.
func Skip(sequence []*WorkflowPattern, input []string) bool {
	allSkipped := true
	for _, file := range input {
		shouldSkip := true
		for _, item := range sequence {
			if item.negative {
				// "!README.md" doesn't match "README.md", so "README.md" should be skipped
				// "!README.md" matches "help.md" but it shouldn't affect "skip or not", because "help.md" might have been skipped by other rules like "docs/*.md"
				if !item.glob.Match(file) {
					shouldSkip = true
				}
			} else if item.glob.Match(file) {
				// if "*.md" matches "help.md" so it shouldn't be skipped
				shouldSkip = false
			}
		}
		allSkipped = allSkipped && shouldSkip
	}
	return len(sequence) > 0 && allSkipped
}

// Filter returns true if the workflow should be skipped per paths-ignore/branches-ignore semantics.
func Filter(sequence []*WorkflowPattern, input []string) bool {
	for _, file := range input {
		anyMatched := false
		for _, item := range sequence {
			if anyMatched = item.glob.Match(file); anyMatched {
				break
			}
		}
		if !anyMatched {
			return false
		}
	}
	return len(sequence) != 0
}
