package admin

import (
	"context"
	"errors"

	"git.dmitriygnatenko.ru/dima/go-common/db"
	"git.dmitriygnatenko.ru/dima/go-common/logger"
	validation "github.com/go-ozzo/ozzo-validation/v4"
	"github.com/gofiber/fiber/v2"

	"git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/dto"
	customErrors "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/helper/errors"
	"git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/mapper"
	"git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/service/i18n"
)

type addTagPage struct {
	tagRepository TagRepository
}

func NewAddTagPageHandler(
	tagRepository TagRepository,
) fiber.Handler {
	h := addTagPage{
		tagRepository: tagRepository,
	}

	return h.handler()
}

func (h addTagPage) handler() fiber.Handler {
	return func(fctx *fiber.Ctx) error {
		ctx := fctx.Context()
		lang := i18n.LanguageFromContext(fctx)
		validationErrors := make(map[string]string)

		var form dto.TagForm

		if fctx.Method() == fiber.MethodPost {
			if err := fctx.BodyParser(&form); err != nil {
				logger.Info(ctx, customErrors.Wrap(err, "add tag page: can't parse body").Error())
				return err
			}

			if err := h.validateTagForm(ctx, form); err != nil {
				logger.Info(ctx, customErrors.Wrap(err, "add tag page: validation").Error())
				validationErrors = mapper.ToErrorsMap(err)
			}

			if len(validationErrors) == 0 {
				err := h.tagRepository.Add(ctx, mapper.ToTagModel(form))
				if err != nil {
					logger.Info(ctx, customErrors.Wrap(err, "add tag page: can't add tag").Error())
					return err
				}

				return fctx.Redirect("/admin/tag")
			}
		}

		return fctx.Render("admin/tag_edit", fiber.Map{
			"lang":    lang,
			"section": "tag",
			"form":    form,
			"errors":  validationErrors,
			"title":   i18n.T(lang, "admin_tag_add_title"),
		}, "admin/_layout")
	}
}

func (h addTagPage) validateTagForm(ctx context.Context, req dto.TagForm) error {
	lang := i18n.DefaultLanguage()
	requiredMsg := i18n.T(lang, "admin_err_required")
	lengthMsg := i18n.T(lang, "admin_err_length_255")

	return validation.ValidateStructWithContext(
		ctx,
		&req,
		validation.Field(
			&req.Tag,
			validation.Required.Error(requiredMsg),
			validation.Length(1, 255).Error(lengthMsg),
		),
		validation.Field(
			&req.URL,
			validation.Required.Error(requiredMsg),
			validation.Length(1, 255).Error(lengthMsg),
			validation.By(h.validateDuplicateURL),
		),
	)
}

func (h addTagPage) validateDuplicateURL(value interface{}) error {
	url, _ := value.(string)
	ctx := context.Background()
	lang := i18n.DefaultLanguage()

	_, err := h.tagRepository.GetByURL(ctx, url)
	if err != nil {
		if !db.IsNotFoundError(err) {
			logger.Error(ctx, err.Error())
		}

		return nil
	}

	return errors.New(i18n.T(lang, "admin_err_tag_duplicate", url))
}
