package api

import (
	"agent/client/events"
	"agent/commons/utils"
	"agent/defines/devent/daction"
	"agent/defines/devent/dcategory"
	"agent/defines/devent/dkind"

	"github.com/google/uuid"
)

type UserGroupCreateArgs struct {
	ProjectUuid uuid.UUID      `json:"project_uuid"`
	Uuid        uuid.UUID      `json:"uuid,omitempty"`
	Name        string         `json:"name"`
	Settings    map[string]any `json:"settings,omitempty"`
	EmptyRights *bool          `json:"empty_rights,omitempty"`
}

func EventUserGroupCreate(args UserGroupCreateArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.UserGroup},
		daction.Create,
		meta,
	), nil
}

func EventUserGroupDelete(uuid uuid.UUID) (IEvent, error) {
	meta := map[string]any{
		"uuid": uuid,
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.UserGroup},
		daction.Delete,
		meta,
	), nil
}

type UserGroupGetArgs struct {
	Uuid        uuid.UUID `json:"uuid,omitempty"`
	ProjectUuid uuid.UUID `json:"project_uuid,omitempty"`
	Name        string    `json:"group_name,omitempty"`
	Raw         *bool     `json:"raw,omitempty"`
	Edit        *bool     `json:"edit,omitempty"`
}

func EventUserGroupGet(args UserGroupGetArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.UserGroup},
		daction.Get,
		meta,
	), nil
}

type UserGroupUpdateArgs struct {
	Uuid     uuid.UUID       `json:"uuid"`
	Name     string          `json:"name,omitempty"`
	Settings map[string]any  `json:"settings,omitempty"`
	Rights   map[string]bool `json:"rights,omitempty"`
}

func EventUserGroupUpdate(args UserGroupUpdateArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.UserGroup},
		daction.Update,
		meta,
	), nil
}

type UserGroupListArgs struct {
	Kind   string                  `json:"kind"`
	Filter UserGroupListFilterOpts `json:"filter,omitempty"`
	Raw    *bool                   `json:"raw,omitempty"`
	Admin  *bool                   `json:"admin,omitempty"`
}

type UserGroupListFilterOpts struct {
	ProjectUuid     uuid.UUID                `json:"project_uuid,omitempty"`
	UserUuid        uuid.UUID                `json:"user_uuid,omitempty"`
	AgentUuid       uuid.UUID                `json:"agent_uuid,omitempty"`
	AgentGroupUuids []uuid.UUID              `json:"agent_group_uuids,omitempty"`
	Search          string                   `json:"search,omitempty"`
	Admin           *bool                    `json:"admin,omitempty"`
	Exclude         UserGroupListExcludeOpts `json:"exclude,omitempty"`
}

type UserGroupListExcludeOpts struct {
	UserGroupUuids  []uuid.UUID `json:"user_group_uuids,omitempty"`
	AgentGroupUuids []uuid.UUID `json:"agent_group_uuids,omitempty"`
	UserUuid        uuid.UUID   `json:"user_uuid,omitempty"`
	Admin           *bool       `json:"admin,omitempty"`
}

func EventUserGroupList(args UserGroupListArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.UserGroup},
		daction.List,
		meta,
	), nil
}

type UserGroupListByProjectAndUserArgs struct {
	ProjectUuid uuid.UUID
	UserUuid    uuid.UUID
	Search      string
	Exclude     *UserGroupListExcludeOpts
	Raw         *bool
	Admin       *bool
	FilterAdmin *bool
}

func EventUserGroupListByProjectAndUser(args UserGroupListByProjectAndUserArgs) (IEvent, error) {
	args_ := UserGroupListArgs{
		Kind: "by_project_and_user",
		Filter: UserGroupListFilterOpts{
			ProjectUuid: args.ProjectUuid,
			UserUuid:    args.UserUuid,
			Search:      args.Search,
			Admin:       args.FilterAdmin,
		},
		Raw:   args.Raw,
		Admin: args.Admin,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventUserGroupList(args_)
}

type UserGroupListByProjectArgs struct {
	ProjectUuid uuid.UUID
	Search      string
	Exclude     *UserGroupListExcludeOpts
	Raw         *bool
	Admin       *bool
	FilterAdmin *bool
}

func EventUserGroupListByProject(args UserGroupListByProjectArgs) (IEvent, error) {
	args_ := UserGroupListArgs{
		Kind: "by_project",
		Filter: UserGroupListFilterOpts{
			ProjectUuid: args.ProjectUuid,
			Search:      args.Search,
			Admin:       args.FilterAdmin,
		},
		Raw:   args.Raw,
		Admin: args.Admin,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventUserGroupList(args_)
}

type UserGroupListByUserArgs struct {
	UserUuid    uuid.UUID
	Search      string
	Exclude     *UserGroupListExcludeOpts
	Raw         *bool
	Admin       *bool
	FilterAdmin *bool
}

func EventUserGroupListByUser(args UserGroupListByUserArgs) (IEvent, error) {
	args_ := UserGroupListArgs{
		Kind: "by_user",
		Filter: UserGroupListFilterOpts{
			UserUuid: args.UserUuid,
			Search:   args.Search,
			Admin:    args.FilterAdmin,
		},
		Raw:   args.Raw,
		Admin: args.Admin,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventUserGroupList(args_)
}

type UserGroupListByAgentGroupsArgs struct {
	AgentGroupUuids []uuid.UUID
	Search          string
	Exclude         *UserGroupListExcludeOpts
	Raw             *bool
	Admin           *bool
	FilterAdmin     *bool
}

func EventUserGroupListByAgentGroups(args UserGroupListByAgentGroupsArgs) (IEvent, error) {
	args_ := UserGroupListArgs{
		Kind: "by_agent_groups",
		Filter: UserGroupListFilterOpts{
			AgentGroupUuids: args.AgentGroupUuids,
			Search:          args.Search,
			Admin:           args.FilterAdmin,
		},
		Raw:   args.Raw,
		Admin: args.Admin,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventUserGroupList(args_)
}

type UserGroupListByAgentArgs struct {
	AgentUuid   uuid.UUID
	Search      string
	Exclude     *UserGroupListExcludeOpts
	Raw         *bool
	Admin       *bool
	FilterAdmin *bool
}

func EventUserGroupListByAgent(args UserGroupListByAgentArgs) (IEvent, error) {
	args_ := UserGroupListArgs{
		Kind: "by_agent",
		Filter: UserGroupListFilterOpts{
			AgentUuid: args.AgentUuid,
			Search:    args.Search,
			Admin:     args.FilterAdmin,
		},
		Raw:   args.Raw,
		Admin: args.Admin,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventUserGroupList(args_)
}

type UserGroupListAllArgs struct {
	Search      string
	Exclude     *UserGroupListExcludeOpts
	Raw         *bool
	Admin       *bool
	FilterAdmin *bool
}

func EventUserGroupListAll(args UserGroupListAllArgs) (IEvent, error) {
	args_ := UserGroupListArgs{
		Kind: "all",
		Filter: UserGroupListFilterOpts{
			Admin:  args.FilterAdmin,
			Search: args.Search,
		},
		Raw:   args.Raw,
		Admin: args.Admin,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventUserGroupList(args_)
}

func EventUserGroupAddUsers(groupUuids []uuid.UUID, userUuids []uuid.UUID) (IEvent, error) {
	meta := map[string]any{
		"group_uuid_list": groupUuids,
		"user_uuid_list":  userUuids,
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.UserGroup, dcategory.User},
		daction.Add,
		meta,
	), nil
}

func EventUserGroupDeleteUsers(groupUuids []uuid.UUID, userUuids []uuid.UUID) (IEvent, error) {
	meta := map[string]any{
		"group_uuid_list": groupUuids,
		"user_uuid_list":  userUuids,
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.UserGroup, dcategory.User},
		daction.Delete,
		meta,
	), nil
}
