/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package basic

import (
	"embed"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/apache/answer-plugins/reviewer-basic/i18n"
	"github.com/apache/answer-plugins/util"
	"github.com/apache/answer/plugin"
	myI18n "github.com/segmentfault/pacman/i18n"
)

//go:embed  info.yaml
var Info embed.FS

type Reviewer struct {
	Config *ReviewerConfig
}

const (
	OptionNone  = "none"
	OptionAll   = "all"
	OptionFirst = "first"
)

type ReviewerConfig struct {
	PostAllNeedReview      bool   `json:"review_post_all"`
	PostNeedReview         bool   `json:"review_post"`
	PostReviewOption       string `json:"review_post_option"`
	PostReviewKeywords     string `json:"review_post_keywords"`
	PostDisallowedKeywords string `json:"disallowed_keywords"`
}

func init() {
	plugin.Register(&Reviewer{
		Config: &ReviewerConfig{},
	})
}

func (r *Reviewer) Info() plugin.Info {
	info := &util.Info{}
	info.GetInfo(Info)

	return plugin.Info{
		Name:        plugin.MakeTranslator(i18n.InfoName),
		SlugName:    info.SlugName,
		Description: plugin.MakeTranslator(i18n.InfoDescription),
		Author:      info.Author,
		Version:     info.Version,
		Link:        info.Link,
	}
}

func (r *Reviewer) Review(content *plugin.ReviewContent) (result *plugin.ReviewResult) {
	result = &plugin.ReviewResult{Approved: true, ReviewStatus: plugin.ReviewStatusApproved}

	// If the author is admin, no need to review
	if content.Author.Role > 1 {
		return result
	}

	if r.Config.PostReviewOption == OptionAll || (r.Config.PostReviewOption == "" && r.Config.PostAllNeedReview) {
		result = &plugin.ReviewResult{
			Approved:     false,
			ReviewStatus: plugin.ReviewStatusNeedReview,
			Reason:       plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentNeedReview, nil),
		}
		return result
	}

	if (r.Config.PostReviewOption == OptionFirst || (r.Config.PostReviewOption == "" && r.Config.PostNeedReview)) && content.Author.ApprovedQuestionAmount+content.Author.ApprovedAnswerAmount == 0 {
		result = &plugin.ReviewResult{
			Approved:     false,
			ReviewStatus: plugin.ReviewStatusNeedReview,
			Reason:       plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentNeedReview, nil),
		}
		return result
	}

	keywords := strings.Split(r.Config.PostReviewKeywords, "\n")
	disallowedKeywords := strings.Split(r.Config.PostDisallowedKeywords, "\n")

	// Check if the post contains the keywords that need review
	for _, keyword := range keywords {
		keyword = strings.TrimSpace(keyword)
		if len(keyword) == 0 {
			continue
		}
		keyword = strings.ToLower(keyword)
		if strings.Contains(strings.ToLower(content.Title), keyword) ||
			strings.Contains(strings.ToLower(content.Content), keyword) ||
			strings.Contains(content.IP, keyword) ||
			strings.Contains(content.UserAgent, keyword) ||
			r.checkTags(content.Tags, keyword) {
			return &plugin.ReviewResult{
				Approved:     false,
				ReviewStatus: plugin.ReviewStatusNeedReview,
				Reason:       fmt.Sprintf(plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentMatchWordReview, nil), keyword),
			}
		}
	}

	// If the post contains the disallowed keywords
	for _, disallowedKeyword := range disallowedKeywords {
		disallowedKeyword = strings.TrimSpace(disallowedKeyword)
		if len(disallowedKeyword) == 0 {
			continue
		}
		disallowedKeyword = strings.ToLower(disallowedKeyword)
		if strings.Contains(strings.ToLower(content.Title), disallowedKeyword) ||
			strings.Contains(strings.ToLower(content.Content), disallowedKeyword) ||
			strings.Contains(content.IP, disallowedKeyword) ||
			strings.Contains(content.UserAgent, disallowedKeyword) ||
			r.checkTags(content.Tags, disallowedKeyword) {
			return &plugin.ReviewResult{
				Approved:     false,
				ReviewStatus: plugin.ReviewStatusDeleteDirectly,
				Reason:       fmt.Sprintf(plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentMatchWordReview, nil), disallowedKeyword),
			}
		}
	}

	return result
}

func (r *Reviewer) ConfigFields() []plugin.ConfigField {
	defaultOption := OptionNone
	if r.Config.PostReviewOption == "" {
		if r.Config.PostAllNeedReview {
			defaultOption = OptionAll
		} else if r.Config.PostNeedReview {
			defaultOption = OptionFirst
		}
	} else {
		defaultOption = r.Config.PostReviewOption
	}

	return []plugin.ConfigField{
		{
			Name:      "review_post_option",
			Type:      plugin.ConfigTypeSelect,
			Title:     plugin.MakeTranslator(i18n.ConfigReviewPostTitle),
			Required:  false,
			UIOptions: plugin.ConfigFieldUIOptions{},
			Value:     defaultOption,
			Options: []plugin.ConfigFieldOption{
				{
					Value: OptionNone,
					Label: plugin.MakeTranslator(i18n.ConfigSelectOption),
				},
				{
					Value: OptionAll,
					Label: plugin.MakeTranslator(i18n.ConfigReviewPostLabelAll),
				},
				{
					Value: OptionFirst,
					Label: plugin.MakeTranslator(i18n.ConfigReviewPostLabelFirst),
				},
			},
		},
		{
			Name:        "review_post_keywords",
			Type:        plugin.ConfigTypeTextarea,
			Title:       plugin.MakeTranslator(i18n.ConfigReviewPostKeywordsTitle),
			Description: plugin.MakeTranslator(i18n.ConfigReviewPostKeywordsDescription),
			Value:       r.Config.PostReviewKeywords,
		},
		{
			Name:        "disallowed_keywords",
			Type:        plugin.ConfigTypeTextarea,
			Title:       plugin.MakeTranslator(i18n.ConfigDisallowedKeywordsTitle),
			Description: plugin.MakeTranslator(i18n.ConfigDisallowedKeywordsDescription),
			Value:       r.Config.PostDisallowedKeywords,
		},
	}
}

func (r *Reviewer) ConfigReceiver(config []byte) error {
	c := &ReviewerConfig{}
	_ = json.Unmarshal(config, c)

	if c.PostReviewOption == OptionAll {
		c.PostAllNeedReview = true
		c.PostNeedReview = false
	} else if c.PostReviewOption == OptionFirst {
		c.PostAllNeedReview = false
		c.PostNeedReview = true
	} else if c.PostReviewOption == OptionNone {
		c.PostAllNeedReview = false
		c.PostNeedReview = false
	}

	r.Config = c
	return nil
}

func (r *Reviewer) checkTags(tags []string, keyword string) bool {
	for _, tag := range tags {
		if strings.Contains(strings.ToLower(tag), keyword) {
			return true
		}
	}
	return false
}
