package checkers

import (
	"go/ast"
	"regexp"
	"strings"

	"github.com/go-critic/go-critic/checkers/internal/astwalk"
	"github.com/go-critic/go-critic/linter"
)

func init() {
	var info linter.CheckerInfo
	info.Name = "codegenComment"
	info.Tags = []string{linter.DiagnosticTag}
	info.Summary = "Detects malformed 'code generated' file comments"
	info.Before = `// This file was automatically generated by foogen`
	info.After = `// Code generated by foogen. DO NOT EDIT.`

	collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
		patterns := []string{
			"this (?:file|code) (?:was|is) auto(?:matically)? generated",
			"this (?:file|code) (?:was|is) generated automatically",
			"this (?:file|code) (?:was|is) generated by",
			"this (?:file|code) (?:was|is) (?:auto(?:matically)? )?generated",
			"this (?:file|code) (?:was|is) generated",
			"code in this file (?:was|is) auto(?:matically)? generated",
			"generated (?:file|code) - do not edit",
			// TODO(quasilyte): more of these.
		}
		re := regexp.MustCompile("(?i)" + strings.Join(patterns, "|"))
		return &codegenCommentChecker{
			ctx:          ctx,
			badCommentRE: re,
		}, nil
	})
}

type codegenCommentChecker struct {
	astwalk.WalkHandler
	ctx *linter.CheckerContext

	badCommentRE *regexp.Regexp
}

func (c *codegenCommentChecker) WalkFile(f *ast.File) {
	if f.Doc == nil {
		return
	}

	for _, comment := range f.Doc.List {
		if c.badCommentRE.MatchString(comment.Text) {
			c.warn(comment)
			return
		}
	}
}

func (c *codegenCommentChecker) warn(cause ast.Node) {
	c.ctx.Warn(cause, "comment should match `Code generated .* DO NOT EDIT.` regexp")
}
