package api

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

type ClientKeyCreateArgs struct {
	ProjectUuid UUID           `json:"project_uuid"`
	Uuid        UUID           `json:"uuid,omitempty"`
	Name        string         `json:"name"`
	Value       string         `json:"value,omitempty"`
	Settings    map[string]any `json:"settings,omitempty"`
	Data        []byte         `json:"-"`
}

func EventClientKeyCreate(args ClientKeyCreateArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	var opts []NewEventOpts
	if len(args.Data) == 0 {
		opts = append(opts, NewEventOpts{
			Data: adata.NewDataFromMem(args.Data),
		})
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Service, dcategory.Client, dcategory.Key},
		daction.Create,
		meta,
		opts...,
	), nil
}

type ClientKeyGetArgs struct {
	Uuid        UUID   `json:"uuid,omitempty"`
	ProjectUuid UUID   `json:"project_uuid,omitempty"`
	Value       string `json:"value,omitempty"`
	Name        string `json:"name,omitempty"`
	Raw         *bool  `json:"raw,omitempty"`
}

func EventClientKeyGet(args ClientKeyGetArgs) (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.Client, dcategory.Key},
		daction.Get,
		meta,
	), nil
}

type ClientKeyUpdateArgs struct {
	Uuid     UUID           `json:"uuid"`
	Name     string         `json:"name,omitempty"`
	Value    string         `json:"value,omitempty"`
	Settings map[string]any `json:"settings,omitempty"`
}

func EventClientKeyUpdate(args ClientKeyUpdateArgs) (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.Client, dcategory.Key},
		daction.Update,
		meta,
	), nil
}

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

type ClientKeyListArgs struct {
	Kind    string                  `json:"kind"`
	Filter  ClientKeyListFilterOpts `json:"filter,omitempty"`
	Offset  int64                   `json:"offset,omitempty"`
	Limit   int64                   `json:"limit,omitempty"`
	Reverse *bool                   `json:"reverse,omitempty"`
	Raw     *bool                   `json:"raw,omitempty"`
}

type ClientKeyListFilterOpts struct {
	ProjectUuid     UUID                     `json:"project_uuid,omitempty"`
	AgentGroupUuids []UUID                   `json:"agent_group_uuids,omitempty"`
	Search          string                   `json:"search,omitempty"`
	Exclude         ClientKeyListExcludeOpts `json:"exclude,omitempty"`
}

type ClientKeyListExcludeOpts struct {
	AgentGroupUuids []UUID `json:"agent_group_uuids,omitempty"`
}

func EventClientKeyList(args ClientKeyListArgs) (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.Client, dcategory.Key},
		daction.List,
		meta,
	), nil
}

type ClientKeyListByProjectArgs struct {
	ProjectUuid UUID
	Search      string
	Exclude     *ClientKeyListExcludeOpts
	Offset      int64
	Limit       int64
	Reverse     *bool
	Raw         *bool
}

func EventClientKeyListByProject(args ClientKeyListByProjectArgs) (IEvent, error) {
	args_ := ClientKeyListArgs{
		Kind: "by_project",
		Filter: ClientKeyListFilterOpts{
			ProjectUuid: args.ProjectUuid,
			Search:      args.Search,
		},
		Offset:  args.Offset,
		Limit:   args.Limit,
		Reverse: args.Reverse,
		Raw:     args.Raw,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventClientKeyList(args_)
}

type ClientKeyListByAgentGroupsArgs struct {
	AgentGroupUuids []UUID
	Search          string
	Exclude         *ClientKeyListExcludeOpts
	Offset          int64
	Limit           int64
	Reverse         *bool
	Raw             *bool
}

func EventClientKeyListByAgentGroups(args ClientKeyListByAgentGroupsArgs) (IEvent, error) {
	args_ := ClientKeyListArgs{
		Kind: "by_agent_groups",
		Filter: ClientKeyListFilterOpts{
			AgentGroupUuids: args.AgentGroupUuids,
			Search:          args.Search,
		},
		Offset:  args.Offset,
		Limit:   args.Limit,
		Reverse: args.Reverse,
		Raw:     args.Raw,
	}
	if args.Exclude != nil {
		args_.Filter.Exclude = *args.Exclude
	}
	return EventClientKeyList(args_)
}

type ClientKeyListAllArgs struct {
	Exclude *ClientKeyListExcludeOpts
	Search  string
	Offset  int64
	Limit   int64
	Reverse *bool
	Raw     *bool
}

func EventClientKeyListAll(args ...ClientKeyListAllArgs) (IEvent, error) {
	args_ := ClientKeyListArgs{
		Kind: "all",
	}
	if len(args) > 0 {
		a := args[0]

		args_.Filter.Search = a.Search

		args_.Offset = a.Offset
		args_.Limit = a.Limit
		args_.Reverse = a.Reverse
		args_.Raw = a.Raw

		if a.Exclude != nil {
			args_.Filter.Exclude = *a.Exclude
		}
	}
	return EventClientKeyList(args_)
}
