package main

import (
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"strings"
)

var (
	errCommitMsgSyntax       = errors.New("commit msg syntax is wrong")
	errCommitMsgInvalideType = errors.New("commit msg type is invalide")
)

var allowedTypes []string

func init() {
	allowedTypes = append(allowedTypes, "fix", "feat", "build", "chore", "ci", "docs", "style", "refactor", "perf", "test")
}
func main() {
	commitMsg, err := getCommitMessageFromFile(os.Args[1])
	if err != nil {
		log.Fatal("Error parsing commitMsg: ", err)
	}

	firstLine, err := getFirstLine(commitMsg)
	if err != nil {
		log.Fatal("Error getting first line of commitMsg: ", err)
	}

	err = checkCommitMsg(firstLine)
	if err != nil {
		fmt.Println("### COMMIT MESSAGES dont match conventions")
		fmt.Println(err)
		fmt.Println("")
		fmt.Println("A valid example is:")
		fmt.Println("feat(lang): add Polish language")
		fmt.Println("valide types are: ", strings.Join(allowedTypes, ", "))
		fmt.Println("see more at: https://www.conventionalcommits.org/en/v1.0.0/")
		os.Exit(1)
	}

	fmt.Println("Commit Message ok")

}

func checkCommitMsg(firstLine string) error {
	r, _ := regexp.Compile("^([a-z]*)(\\([^\\)]*\\))?!?:")
	results := r.FindStringSubmatch(firstLine)
	if len(results) < 3 {
		return errCommitMsgSyntax
	}

	if !CheckTyp(results[1]) {
		return errCommitMsgInvalideType
	}

	return nil
}

func CheckTyp(ty string) bool {
	for _, t := range allowedTypes {
		if t == ty {
			return true
		}
	}
	return false
}

func getFirstLine(commitMsg string) (string, error) {
	lines := strings.Split(commitMsg, "\n")
	return lines[0], nil
}

func getCommitMessageFromFile(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", fmt.Errorf("cant open commit msg file: %w", err)
	}
	defer f.Close()

	buf := make([]byte, 1024)
	commitmsg := ""
	for {
		n, err := f.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", fmt.Errorf("cant read from commit-msg file: %w", err)
		}
		if n > 0 {
			commitmsg += string(buf[:n])
		}
	}

	return commitmsg, nil
}
