package linter

import (
	"strings"

	"alpinelinux.org/go/atools/apkbuild"
	"alpinelinux.org/go/atools/internal/ranges"
	"mvdan.cc/sh/v3/syntax"
)

var (
	AL7 LintingViolation = LintingViolation{
		Code:        "AL7",
		Description: "indent with tabs",
		Certainty:   Certain,
		Severity:    Important,
		Skip:        "INDENT_TABS",
	}

	AL8 LintingViolation = LintingViolation{
		Code:        "AL8",
		Description: "trailing whitespace",
		Certainty:   Certain,
		Severity:    Important,
		Skip:        "TRAILING_WHITESPACE",
	}
)

func init() {
	Register(&AL7, CheckIndentTabs)
	Register(&AL8, CheckTrailingWhitespace)
}

func getHeredocRanges(heredocs []*syntax.Word) (rs ranges.Ranges) {
	for _, heredoc := range heredocs {
		start := heredoc.Parts[0].Pos().Line()
		// Last line includes the end of heredoc marker, which should be excluded.
		end := heredoc.Parts[len(heredoc.Parts)-1].End().Line() - 1
		rs = append(rs, ranges.Range{Min: int(start), Max: int(end)})
	}

	return rs
}

func CheckIndentTabs(apkbuild *apkbuild.Apkbuild, getenv func(string) string) (violations []LintingViolation) {
	hereDocRanges := getHeredocRanges(apkbuild.Heredocs)
	for nr, line := range apkbuild.Lines {
		if hereDocRanges.IsWithinAny(nr) {
			continue
		}
		if strings.HasPrefix(line, "  ") {
			violations = append(violations, AL7.Instantiate(apkbuild.File.Name, uint(nr+1), 1))
		}
	}

	return
}

func CheckTrailingWhitespace(apkbuild *apkbuild.Apkbuild, getenv func(string) string) (violations []LintingViolation) {
	for nr, line := range apkbuild.Lines {
		if strings.HasSuffix(line, " ") {
			violations = append(violations, AL8.Instantiate(apkbuild.File.Name, uint(nr+1), 1))
		}
	}

	return
}
