package main

import (
	"errors"
	"fmt"

	"github.com/larkox/mattermost-plugin-badges/badgesmodel"
	commandparser "github.com/larkox/mattermost-plugin-badges/server/command_parser"
	"github.com/mattermost/mattermost-server/v5/model"
	"github.com/mattermost/mattermost-server/v5/plugin"
	"github.com/spf13/pflag"
)

func getHelp() string {
	return `Available Commands:
`
}

func (p *Plugin) getCommand() *model.Command {
	return &model.Command{
		Trigger:          "badges",
		DisplayName:      "Achievements Bot",
		Description:      "Achievements",
		AutoComplete:     true,
		AutoCompleteDesc: "Available commands:",
		AutoCompleteHint: "[command]",
		AutocompleteData: p.getAutocompleteData(),
	}
}

func (p *Plugin) postCommandResponse(args *model.CommandArgs, text string) {
	post := &model.Post{
		UserId:    p.BotUserID,
		ChannelId: args.ChannelId,
		Message:   text,
	}
	p.mm.Post.SendEphemeralPost(args.UserId, post)
}

func commandError(text string) (bool, *model.CommandResponse, error) {
	return true, &model.CommandResponse{}, errors.New(text)
}

// ExecuteCommand executes a given command and returns a command response.
func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
	stringArgs := commandparser.Parse(args.Command)
	lengthOfArgs := len(stringArgs)
	restOfArgs := []string{}

	var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
	if lengthOfArgs == 1 {
		p.postCommandResponse(args, getHelp())
		return &model.CommandResponse{}, nil
	}
	command := stringArgs[1]
	if lengthOfArgs > 2 {
		restOfArgs = stringArgs[2:]
	}
	switch command {
	case "test-clean":
		handler = p.runClean
	case "grant":
		handler = p.runGrant
	case "edit":
		handler = p.runEdit
	case "create":
		handler = p.runCreate
	case "subscription":
		handler = p.runSubscription
	default:
		p.postCommandResponse(args, getHelp())
		return &model.CommandResponse{}, nil
	}
	isUserError, resp, err := handler(restOfArgs, args)
	if err != nil {
		if isUserError {
			p.postCommandResponse(args, fmt.Sprintf("__Error: %s__", err.Error()))
		} else {
			p.mm.Log.Error(err.Error())
			u, _ := p.mm.User.Get(args.UserId)
			locale := "ru"
			if u != nil {
				locale = u.Locale
			}
			T := p.getT(locale)
			p.postCommandResponse(args, T("badges.error.unknown", "Произошла неизвестная ошибка. Обратитесь к системному администратору."))
		}
	}

	if resp != nil {
		return resp, nil
	}

	return &model.CommandResponse{}, nil
}

func (p *Plugin) runClean(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	user, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return false, &model.CommandResponse{Text: "Cannot get user."}, nil
	}
	T := p.getT(user.Locale)
	if !user.IsSystemAdmin() {
		return false, &model.CommandResponse{Text: T("badges.error.only_sysadmin_clean", "Только системный администратор может очистить базу значков.")}, nil
	}
	_ = p.mm.KV.DeleteAll()
	return false, &model.CommandResponse{Text: T("badges.success.clean", "Очищено")}, nil
}

func (p *Plugin) runCreate(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	lengthOfArgs := len(args)
	restOfArgs := []string{}
	var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
	if lengthOfArgs == 0 {
		u, _ := p.mm.User.Get(extra.UserId)
		locale := "ru"
		if u != nil {
			locale = u.Locale
		}
		T := p.getT(locale)
		return false, &model.CommandResponse{Text: T("badges.error.specify_create", "Укажите, что вы хотите создать.")}, nil
	}
	command := args[0]
	if lengthOfArgs > 1 {
		restOfArgs = args[1:]
	}
	switch command {
	case "badge":
		handler = p.runCreateBadge
	case "type":
		handler = p.runCreateType
	default:
		u, _ := p.mm.User.Get(extra.UserId)
		locale := "ru"
		if u != nil {
			locale = u.Locale
		}
		T := p.getT(locale)
		return false, &model.CommandResponse{Text: T("badges.error.create_badge_or_type", "Можно создать badge или type")}, nil
	}

	return handler(restOfArgs, extra)
}

func (p *Plugin) runCreateBadge(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	u, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return commandError(err.Error())
	}
	T := p.getT(u.Locale)

	typeSuggestions, err := p.filterCreateBadgeTypes(u)
	if err != nil {
		return commandError(err.Error())
	}

	typeOptions := []*model.PostActionOptions{}
	for _, typeSuggestion := range typeSuggestions {
		id := string(typeSuggestion.ID)
		typeOptions = append(typeOptions, &model.PostActionOptions{Text: typeSuggestion.Name, Value: id})
	}

	if len(typeOptions) == 0 {
		return commandError(T("badges.error.no_types_available", "Вы не можете создать значки ни одного типа."))
	}

	err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
		TriggerId: extra.TriggerId,
		URL:       p.getDialogURL() + DialogPathCreateBadge,
		Dialog: model.Dialog{
			Title:       T("badges.dialog.create_badge.title", "Создать значок"),
			SubmitLabel: T("badges.dialog.create_badge.submit", "Создать"),
			Elements: []model.DialogElement{
				{
					DisplayName: T("badges.field.name", "Название"),
					Type:        "text",
					Name:        DialogFieldBadgeName,
					MaxLength:   badgesmodel.NameMaxLength,
				},
				{
					DisplayName: T("badges.field.description", "Описание"),
					Type:        "text",
					Name:        DialogFieldBadgeDescription,
					MaxLength:   badgesmodel.DescriptionMaxLength,
				},
				{
					DisplayName: T("badges.field.image", "Изображение"),
					Type:        "text",
					Name:        DialogFieldBadgeImage,
					HelpText:    T("badges.field.image.help", "Введите название эмодзи"),
				},
				{
					DisplayName: T("badges.field.type", "Тип"),
					Type:        "select",
					Name:        DialogFieldBadgeType,
					Options:     typeOptions,
				},
				{
					DisplayName: T("badges.field.multiple", "Многократный"),
					Type:        "bool",
					Name:        DialogFieldBadgeMultiple,
					HelpText:    T("badges.field.multiple.help", "Можно ли выдавать этот значок несколько раз"),
					Optional:    true,
				},
			},
		},
	})

	if err != nil {
		return commandError(err.Error())
	}

	return false, &model.CommandResponse{}, nil
}

func (p *Plugin) runEdit(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	lengthOfArgs := len(args)
	restOfArgs := []string{}
	var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
	if lengthOfArgs == 0 {
		u, _ := p.mm.User.Get(extra.UserId)
		locale := "ru"
		if u != nil {
			locale = u.Locale
		}
		T := p.getT(locale)
		return false, &model.CommandResponse{Text: T("badges.error.specify_edit", "Укажите, что вы хотите отредактировать.")}, nil
	}
	command := args[0]
	if lengthOfArgs > 1 {
		restOfArgs = args[1:]
	}
	switch command {
	case "badge":
		handler = p.runEditBadge
	case "type":
		handler = p.runEditType
	default:
		u, _ := p.mm.User.Get(extra.UserId)
		locale := "ru"
		if u != nil {
			locale = u.Locale
		}
		T := p.getT(locale)
		return false, &model.CommandResponse{Text: T("badges.error.edit_badge_or_type", "Можно редактировать badge или type")}, nil
	}

	return handler(restOfArgs, extra)
}

func (p *Plugin) runEditBadge(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	u, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return commandError(err.Error())
	}
	T := p.getT(u.Locale)

	var badgeIDStr string
	fs := pflag.NewFlagSet("", pflag.ContinueOnError)
	fs.StringVar(&badgeIDStr, "id", "", "ID of the badge")
	if err = fs.Parse(args); err != nil {
		return commandError(err.Error())
	}

	if badgeIDStr == "" {
		return commandError(T("badges.error.must_set_badge_id", "Необходимо указать ID значка"))
	}

	badge, err := p.store.GetBadge(badgesmodel.BadgeID(badgeIDStr))
	if err != nil {
		return commandError(err.Error())
	}

	badgeType, err := p.store.GetType(badge.Type)
	if err != nil {
		return commandError(err.Error())
	}

	if !canEditBadge(u, p.badgeAdminUserIDs, badge, badgeType) {
		return commandError(T("badges.error.cannot_edit_badge", "У вас нет прав на редактирование этого значка"))
	}

	typeSuggestions, err := p.filterCreateBadgeTypes(u)
	if err != nil {
		return commandError(err.Error())
	}

	typeOptions := []*model.PostActionOptions{}
	for _, typeSuggestion := range typeSuggestions {
		id := string(typeSuggestion.ID)
		typeOptions = append(typeOptions, &model.PostActionOptions{Text: typeSuggestion.Name, Value: id})
	}

	if len(typeOptions) == 0 {
		return commandError(T("badges.error.no_types_available", "Вы не можете создать значки ни одного типа."))
	}

	err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
		TriggerId: extra.TriggerId,
		URL:       p.getDialogURL() + DialogPathEditBadge,
		Dialog: model.Dialog{
			Title:       T("badges.dialog.edit_badge.title", "Редактировать значок"),
			SubmitLabel: T("badges.dialog.edit_badge.submit", "Сохранить"),
			State:       string(badge.ID),
			Elements: []model.DialogElement{
				{
					DisplayName: T("badges.field.name", "Название"),
					Type:        "text",
					Name:        DialogFieldBadgeName,
					MaxLength:   badgesmodel.NameMaxLength,
					Default:     badge.Name,
				},
				{
					DisplayName: T("badges.field.description", "Описание"),
					Type:        "text",
					Name:        DialogFieldBadgeDescription,
					MaxLength:   badgesmodel.DescriptionMaxLength,
					Default:     badge.Description,
				},
				{
					DisplayName: T("badges.field.image", "Изображение"),
					Type:        "text",
					Name:        DialogFieldBadgeImage,
					HelpText:    T("badges.field.image.help", "Введите название эмодзи"),
					Default:     badge.Image,
				},
				{
					DisplayName: T("badges.field.type", "Тип"),
					Type:        "select",
					Name:        DialogFieldBadgeType,
					Options:     typeOptions,
					Default:     string(badge.Type),
				},
				{
					DisplayName: T("badges.field.multiple", "Многократный"),
					Type:        "bool",
					Name:        DialogFieldBadgeMultiple,
					HelpText:    T("badges.field.multiple.help", "Можно ли выдавать этот значок несколько раз"),
					Optional:    true,
					Default:     getBooleanString(badge.Multiple),
				},
				{
					DisplayName: T("badges.field.delete_badge", "Удалить значок"),
					Type:        "bool",
					Name:        DialogFieldBadgeDelete,
					HelpText:    T("badges.field.delete_badge.help", "ВНИМАНИЕ: если отметить, значок будет удалён безвозвратно."),
					Optional:    true,
				},
			},
		},
	})

	if err != nil {
		return commandError(err.Error())
	}

	return false, &model.CommandResponse{}, nil
}

func (p *Plugin) runEditType(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	u, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return commandError(err.Error())
	}
	T := p.getT(u.Locale)

	if !canCreateType(u, p.badgeAdminUserIDs, false) {
		return commandError(T("badges.error.no_permissions_edit_type", "У вас нет прав на редактирование типа значков."))
	}

	var badgeTypeStr string
	fs := pflag.NewFlagSet("", pflag.ContinueOnError)
	fs.StringVar(&badgeTypeStr, "type", "", "ID of the type")
	if err = fs.Parse(args); err != nil {
		return commandError(err.Error())
	}

	if badgeTypeStr == "" {
		return commandError(T("badges.error.must_provide_type_id", "Необходимо указать ID типа"))
	}

	typeDefinition, err := p.store.GetType(badgesmodel.BadgeType(badgeTypeStr))
	if err != nil {
		return commandError(err.Error())
	}

	if !canEditType(u, p.badgeAdminUserIDs, typeDefinition) {
		return commandError(T("badges.error.cannot_edit_type", "У вас нет прав на редактирование этого типа"))
	}

	canGrantAllowList := ""
	for uID, allowed := range typeDefinition.CanGrant.AllowList {
		if !allowed {
			continue
		}
		var allowedUser *model.User
		allowedUser, err = p.mm.User.Get(uID)
		if err != nil {
			continue
		}
		if canGrantAllowList == "" {
			canGrantAllowList += allowedUser.Username
			continue
		}

		canGrantAllowList += ", " + allowedUser.Username
	}

	canCreateAllowList := ""
	for uID, allowed := range typeDefinition.CanCreate.AllowList {
		if !allowed {
			continue
		}
		var allowedUser *model.User
		allowedUser, err = p.mm.User.Get(uID)
		if err != nil {
			continue
		}
		if canCreateAllowList == "" {
			canCreateAllowList += allowedUser.Username
			continue
		}

		canCreateAllowList += ", " + allowedUser.Username
	}

	err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
		TriggerId: extra.TriggerId,
		URL:       p.getDialogURL() + DialogPathEditType,
		Dialog: model.Dialog{
			Title:       T("badges.dialog.edit_type.title", "Редактировать тип"),
			SubmitLabel: T("badges.dialog.edit_type.submit", "Сохранить"),
			State:       badgeTypeStr,
			Elements: []model.DialogElement{
				{
					DisplayName: T("badges.field.name", "Название"),
					Type:        "text",
					Name:        DialogFieldTypeName,
					MaxLength:   badgesmodel.NameMaxLength,
					Default:     typeDefinition.Name,
				},
				{
					DisplayName: T("badges.field.everyone_can_create", "Все могут создавать значки"),
					Type:        "bool",
					Name:        DialogFieldTypeEveryoneCanCreate,
					HelpText:    T("badges.field.everyone_can_create.help", "Любой пользователь может создать значок этого типа"),
					Optional:    true,
					Default:     getBooleanString(typeDefinition.CanCreate.Everyone),
				},
				{
					DisplayName: T("badges.field.allowlist_create", "Список допущенных к созданию"),
					Type:        "text",
					Name:        DialogFieldTypeAllowlistCanCreate,
					HelpText:    T("badges.field.allowlist_create.help", "Укажите имена пользователей через запятую (,), которые могут создавать значки этого типа."),
					Placeholder: "user-1, user-2, user-3",
					Optional:    true,
					Default:     canCreateAllowList,
				},
				{
					DisplayName: T("badges.field.everyone_can_grant", "Все могут выдавать значки"),
					Type:        "bool",
					Name:        DialogFieldTypeEveryoneCanGrant,
					HelpText:    T("badges.field.everyone_can_grant.help", "Любой пользователь может выдать значок этого типа"),
					Optional:    true,
					Default:     getBooleanString(typeDefinition.CanGrant.Everyone),
				},
				{
					DisplayName: T("badges.field.allowlist_grant", "Список допущенных к выдаче"),
					Type:        "text",
					Name:        DialogFieldTypeAllowlistCanGrant,
					HelpText:    T("badges.field.allowlist_grant.help", "Укажите имена пользователей через запятую (,), которые могут выдавать значки этого типа."),
					Placeholder: "user-1, user-2, user-3",
					Optional:    true,
					Default:     canGrantAllowList,
				},
				{
					DisplayName: T("badges.field.delete_type", "Удалить тип"),
					Type:        "bool",
					Name:        DialogFieldTypeDelete,
					HelpText:    T("badges.field.delete_type.help", "ВНИМАНИЕ: если отметить, этот тип и все связанные значки будут удалены безвозвратно."),
					Optional:    true,
				},
			},
		},
	})

	if err != nil {
		return commandError(err.Error())
	}

	return false, &model.CommandResponse{}, nil
}

func (p *Plugin) runCreateType(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	u, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return commandError(err.Error())
	}
	T := p.getT(u.Locale)

	if !canCreateType(u, p.badgeAdminUserIDs, false) {
		return commandError(T("badges.error.no_permissions_create_type", "У вас нет прав на создание типа значков."))
	}

	err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
		TriggerId: extra.TriggerId,
		URL:       p.getDialogURL() + DialogPathCreateType,
		Dialog: model.Dialog{
			Title:       T("badges.dialog.create_type.title", "Создать тип"),
			SubmitLabel: T("badges.dialog.create_type.submit", "Создать"),
			Elements: []model.DialogElement{
				{
					DisplayName: T("badges.field.name", "Название"),
					Type:        "text",
					Name:        DialogFieldTypeName,
					MaxLength:   badgesmodel.NameMaxLength,
				},
				{
					DisplayName: T("badges.field.everyone_can_create", "Все могут создавать значки"),
					Type:        "bool",
					Name:        DialogFieldTypeEveryoneCanCreate,
					HelpText:    T("badges.field.everyone_can_create.help", "Любой пользователь может создать значок этого типа"),
					Optional:    true,
				},
				{
					DisplayName: T("badges.field.allowlist_create", "Список допущенных к созданию"),
					Type:        "text",
					Name:        DialogFieldTypeAllowlistCanCreate,
					HelpText:    T("badges.field.allowlist_create.help", "Укажите имена пользователей через запятую (,), которые могут создавать значки этого типа."),
					Placeholder: "user-1, user-2, user-3",
					Optional:    true,
				},
				{
					DisplayName: T("badges.field.everyone_can_grant", "Все могут выдавать значки"),
					Type:        "bool",
					Name:        DialogFieldTypeEveryoneCanGrant,
					HelpText:    T("badges.field.everyone_can_grant.help", "Любой пользователь может выдать значок этого типа"),
					Optional:    true,
				},
				{
					DisplayName: T("badges.field.allowlist_grant", "Список допущенных к выдаче"),
					Type:        "text",
					Name:        DialogFieldTypeAllowlistCanGrant,
					HelpText:    T("badges.field.allowlist_grant.help", "Укажите имена пользователей через запятую (,), которые могут выдавать значки этого типа."),
					Placeholder: "user-1, user-2, user-3",
					Optional:    true,
				},
			},
		},
	})

	if err != nil {
		return commandError(err.Error())
	}

	return false, &model.CommandResponse{}, nil
}

func (p *Plugin) runGrant(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	badgeStr := ""
	username := ""
	fs := pflag.NewFlagSet("", pflag.ContinueOnError)
	fs.StringVar(&badgeStr, "badge", "", "ID of the badge")
	fs.StringVar(&username, "user", "", "Username to grant to")
	if err := fs.Parse(args); err != nil {
		return commandError(err.Error())
	}

	if username != "" && badgeStr != "" {
		if username[0] == '@' {
			username = username[1:]
		}

		granter, err := p.mm.User.Get(extra.UserId)
		if err != nil {
			return commandError(err.Error())
		}
		T := p.getT(granter.Locale)

		badge, err := p.store.GetBadge(badgesmodel.BadgeID(badgeStr))
		if err != nil {
			return commandError(err.Error())
		}

		badgeType, err := p.store.GetType(badge.Type)
		if err != nil {
			return commandError(err.Error())
		}

		if !canGrantBadge(granter, p.badgeAdminUserIDs, badge, badgeType) {
			return commandError(T("badges.error.no_permissions_grant", "У вас нет прав на выдачу этого значка"))
		}

		user, err := p.mm.User.GetByUsername(username)
		if err != nil {
			return commandError(err.Error())
		}

		shouldNotify, err := p.store.GrantBadge(badgesmodel.BadgeID(badgeStr), user.Id, extra.UserId, "")
		if err == errAlreadyOwned {
			return commandError(T("badges.error.already_owned", "Это достижение уже выдано этому пользователю"))
		}
		if err != nil {
			return commandError(err.Error())
		}

		if shouldNotify {
			p.notifyGrant(badgesmodel.BadgeID(badgeStr), extra.UserId, user, false, "", "")
		}

		p.postCommandResponse(extra, T("badges.success.granted", "Выдано"))
		return false, &model.CommandResponse{}, nil
	}

	actingUser, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return commandError(err.Error())
	}
	T := p.getT(actingUser.Locale)

	elements := []model.DialogElement{}

	stateText := ""
	introductionText := ""
	if username != "" {
		if username[0] == '@' {
			username = username[1:]
		}

		user, err := p.mm.User.GetByUsername(username)
		if err != nil {
			return commandError(err.Error())
		}

		introductionText = T("badges.dialog.grant.intro", "Выдать значок пользователю @%s", username)
		stateText = user.Id
	}

	if stateText == "" {
		elements = append(elements, model.DialogElement{
			DisplayName: T("badges.field.user", "Пользователь"),
			Type:        "select",
			Name:        DialogFieldUser,
			DataSource:  "users",
		})
	}

	options := []*model.PostActionOptions{}
	grantableBadges, err := p.filterGrantBadges(actingUser)
	if err != nil {
		return commandError(err.Error())
	}
	for _, badge := range grantableBadges {
		options = append(options, &model.PostActionOptions{Text: badge.Name, Value: string(badge.ID)})
	}

	badgeElement := model.DialogElement{
		DisplayName: T("badges.field.badge", "Значок"),
		Type:        "select",
		Name:        DialogFieldBadge,
		Options:     options,
	}

	if badgeStr != "" {
		found := false
		for _, badge := range grantableBadges {
			if badgeStr == string(badge.ID) {
				found = true
				break
			}
		}

		if !found {
			return commandError(T("badges.error.cannot_grant_badge", "Вы не можете выдать этот значок"))
		}

		badgeElement.Default = badgeStr
	}

	elements = append(elements, badgeElement)

	elements = append(elements, model.DialogElement{
		DisplayName: T("badges.field.reason", "Причина"),
		Name:        DialogFieldGrantReason,
		Optional:    true,
		HelpText:    T("badges.field.reason.help", "Причина выдачи значка. Будет видна пользователю и в уведомлениях о выдаче (например, в подписках)."),
		Type:        "text",
	})

	elements = append(elements, model.DialogElement{
		DisplayName: T("badges.field.notify_here", "Уведомить в этом канале"),
		Name:        DialogFieldNotifyHere,
		Type:        "bool",
		HelpText:    T("badges.field.notify_here.help", "Если отметить, бот отправит сообщение в этот канал о том, что вы выдали значок этому пользователю."),
		Optional:    true,
	})

	err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
		TriggerId: extra.TriggerId,
		URL:       p.getDialogURL() + DialogPathGrant,
		Dialog: model.Dialog{
			Title:            T("badges.dialog.grant.title", "Выдать значок"),
			IntroductionText: introductionText,
			SubmitLabel:      T("badges.dialog.grant.submit", "Выдать"),
			Elements:         elements,
			State:            stateText,
		},
	})

	if err != nil {
		return commandError(err.Error())
	}

	return false, &model.CommandResponse{}, nil
}

func (p *Plugin) runSubscription(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	lengthOfArgs := len(args)
	restOfArgs := []string{}
	var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
	if lengthOfArgs == 0 {
		u, _ := p.mm.User.Get(extra.UserId)
		locale := "ru"
		if u != nil {
			locale = u.Locale
		}
		T := p.getT(locale)
		return false, &model.CommandResponse{Text: T("badges.error.specify_subscription", "Укажите, что вы хотите сделать.")}, nil
	}
	command := args[0]
	if lengthOfArgs > 1 {
		restOfArgs = args[1:]
	}
	switch command {
	case "create":
		handler = p.runCreateSubscription
	case "remove":
		handler = p.runDeleteSubscription
	default:
		u, _ := p.mm.User.Get(extra.UserId)
		locale := "ru"
		if u != nil {
			locale = u.Locale
		}
		T := p.getT(locale)
		return false, &model.CommandResponse{Text: T("badges.error.create_or_delete_subscription", "Можно создать или удалить подписку")}, nil
	}

	return handler(restOfArgs, extra)
}

func (p *Plugin) runCreateSubscription(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	typeStr := ""
	fs := pflag.NewFlagSet("", pflag.ContinueOnError)
	fs.StringVar(&typeStr, "type", "", "ID of the badge")
	if err := fs.Parse(args); err != nil {
		return commandError(err.Error())
	}

	actingUser, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return commandError(err.Error())
	}
	T := p.getT(actingUser.Locale)

	if !canCreateSubscription(actingUser, p.badgeAdminUserIDs, extra.ChannelId) {
		return commandError(T("badges.error.cannot_create_subscription", "Вы не можете создавать подписки"))
	}

	if typeStr != "" {

		err = p.store.AddSubscription(badgesmodel.BadgeType(typeStr), extra.ChannelId)
		if err != nil {
			return commandError(err.Error())
		}

		p.postCommandResponse(extra, T("badges.success.granted", "Выдано"))
		return false, &model.CommandResponse{}, nil
	}

	options := []*model.PostActionOptions{}
	typesDefinitions, err := p.filterEditTypes(actingUser)
	if err != nil {
		return commandError(err.Error())
	}
	for _, typeDefinition := range typesDefinitions {
		options = append(options, &model.PostActionOptions{Text: typeDefinition.Name, Value: string(typeDefinition.ID)})
	}

	err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
		TriggerId: extra.TriggerId,
		URL:       p.getDialogURL() + DialogPathCreateSubscription,
		Dialog: model.Dialog{
			Title:            T("badges.dialog.create_subscription.title", "Создать подписку"),
			IntroductionText: T("badges.dialog.create_subscription.intro", "Выберите тип значка, на который хотите подписать этот канал."),
			SubmitLabel:      T("badges.dialog.create_subscription.submit", "Добавить"),
			Elements: []model.DialogElement{
				{
					DisplayName: T("badges.field.type", "Тип"),
					Type:        "select",
					Name:        DialogFieldBadgeType,
					Options:     options,
				},
			},
		},
	})

	if err != nil {
		return commandError(err.Error())
	}

	return false, &model.CommandResponse{}, nil
}

func (p *Plugin) runDeleteSubscription(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
	typeStr := ""
	fs := pflag.NewFlagSet("", pflag.ContinueOnError)
	fs.StringVar(&typeStr, "type", "", "ID of the badge")
	if err := fs.Parse(args); err != nil {
		return commandError(err.Error())
	}

	actingUser, err := p.mm.User.Get(extra.UserId)
	if err != nil {
		return commandError(err.Error())
	}
	T := p.getT(actingUser.Locale)

	if !canCreateSubscription(actingUser, p.badgeAdminUserIDs, extra.ChannelId) {
		return commandError(T("badges.error.cannot_create_subscription", "Вы не можете создавать подписки"))
	}

	if typeStr != "" {
		err = p.store.RemoveSubscriptions(badgesmodel.BadgeType(typeStr), extra.ChannelId)
		if err != nil {
			return commandError(err.Error())
		}

		p.postCommandResponse(extra, T("badges.success.removed", "Удалено"))
		return false, &model.CommandResponse{}, nil
	}

	options := []*model.PostActionOptions{}
	typesDefinitions, err := p.store.GetChannelSubscriptions(extra.ChannelId)
	if err != nil {
		return commandError(err.Error())
	}
	for _, typeDefinition := range typesDefinitions {
		options = append(options, &model.PostActionOptions{Text: typeDefinition.Name, Value: string(typeDefinition.ID)})
	}

	err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
		TriggerId: extra.TriggerId,
		URL:       p.getDialogURL() + DialogPathDeleteSubscription,
		Dialog: model.Dialog{
			Title:            T("badges.dialog.delete_subscription.title", "Удалить подписку"),
			IntroductionText: T("badges.dialog.delete_subscription.intro", "Выберите тип значка, подписку на который хотите удалить из этого канала."),
			SubmitLabel:      T("badges.dialog.delete_subscription.submit", "Удалить"),
			Elements: []model.DialogElement{
				{
					DisplayName: T("badges.field.type", "Тип"),
					Type:        "select",
					Name:        DialogFieldBadgeType,
					Options:     options,
				},
			},
		},
	})

	if err != nil {
		return commandError(err.Error())
	}

	return false, &model.CommandResponse{}, nil
}

func (p *Plugin) getAutocompleteData() *model.AutocompleteData {
	badges := model.NewAutocompleteData("badges", "[command]", "Available commands: grant")

	grant := model.NewAutocompleteData("grant", "--user @username --badge id", "Grant a badge to a user")
	grant.AddNamedDynamicListArgument("badge", "--badge badgeID", getAutocompletePath(AutocompletePathBadgeSuggestions), true)
	grant.AddNamedTextArgument("user", "User to grant the badge to", "--user @username", "", true)
	badges.AddCommand(grant)

	create := model.NewAutocompleteData("create", "badge | type", "Create a badge or a type")

	badge := model.NewAutocompleteData(
		"badge",
		"",
		"Create a badge",
	)
	create.AddCommand(badge)

	createType := model.NewAutocompleteData(
		"type",
		"",
		"Create a badge type",
	)
	create.AddCommand(createType)

	badges.AddCommand(create)

	edit := model.NewAutocompleteData("edit", "badge | type", "Edit a badge or a type")

	editBadge := model.NewAutocompleteData(
		"badge",
		"",
		"Edit a badge",
	)
	editBadge.AddNamedDynamicListArgument("id", "--id badgeID", getAutocompletePath(AutocompletePathEditBadgeSuggestions), true)
	edit.AddCommand(editBadge)

	editType := model.NewAutocompleteData(
		"type",
		"",
		"Edit a badge type",
	)
	editType.AddNamedDynamicListArgument("type", "--type typeID", getAutocompletePath(AutocompletePathEditTypeSuggestions), true)
	edit.AddCommand(editType)

	badges.AddCommand(edit)

	subscription := model.NewAutocompleteData("subscription", "create | remove", "Manage this channel subscriptions")

	createSubscription := model.NewAutocompleteData(
		"create",
		"",
		"Create a subscription",
	)
	subscription.AddCommand(createSubscription)

	deleteSubscription := model.NewAutocompleteData(
		"remove",
		"",
		"Remove a subscription",
	)
	subscription.AddCommand(deleteSubscription)

	badges.AddCommand(subscription)

	return badges
}

func getAutocompletePath(path string) string {
	return "plugins/" + manifest.Id + AutocompletePath + path
}
