package api

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

func EventRfsReset(agentUuid UUID) (IEvent, error) {
	meta := map[string]any{
		"agent_uuid": agentUuid,
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Agent, dcategory.Rfs},
		daction.Reset,
		meta,
		events.NewEventOpts{},
	), nil
}

type RfsListActionStatusArgs struct {
	Kind      string                        `json:"kind"`
	Filter    RfsListActionStatusFilterOpts `json:"filter,omitempty"`
	AgentUuid UUID                          `json:"agent_uuid"`
	Offset    int64                         `json:"offset,omitempty"`
	Limit     int64                         `json:"limit,omitempty"`
	Reverse   bool                          `json:"reverse,omitempty"`
}

type RfsListActionStatusFilterOpts struct {
	Actions []RfsAction `json:"actions"`
	Types   []RfsType   `json:"types"`
	Search  string      `json:"search"`
}

func EventRfsListActionStatus(args RfsListActionStatusArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Action, dcategory.Status},
		daction.List,
		meta,
		events.NewEventOpts{},
	), nil
}

type RfsCreateFileArgs struct {
	Path      string `json:"path"`
	LocalPath string `json:"local_path"`
	Rewrite   bool   `json:"rewrite"`

	Data adata.IData `json:"-"`
	Dest Dest        `json:"-"`

	// При указании переопределит стандартные опции запроса и ответа
	RequestOpts  *EventRequestOpts  `json:"-"`
	ResponseOpts *EventResponseOpts `json:"-"`
}

func EventRfsCreateFile(args RfsCreateFileArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{}
	if args.Data != nil {
		opts.Data = args.Data

		size, err := args.Data.Size()
		if err != nil {
			return nil, err
		}

		if size > 0 && size > 4*1024 {
			opts.DataMaxSize = size
			opts.Request = &EventRequestOpts{
				Handler: dhandlers.OctetStream,
				Binary:  utils.PointerTo(true),
			}
			opts.Response = &EventResponseOpts{
				Handler: `application/octet-stream`,
				Type:    `application/octet-stream`,
			}
		}
	}

	if args.RequestOpts != nil {
		opts.Request = args.RequestOpts
	}
	if args.ResponseOpts != nil {
		opts.Response = args.ResponseOpts
	}

	opts.Dest = args.Dest

	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.File},
		daction.Create,
		meta,
		opts,
	), nil
}

type RfsGetFileArgs struct {
	Path        string           `json:"path"`
	DataMaxSize int64            `json:"data_max_size,omitempty"`
	SaveTo      RfsGetFileSaveTo `json:"save_to"`

	Dest events.Dest `json:"-"`
}

type RfsGetFileSaveTo struct {
	Path    string `json:"path"`
	IsDir   bool   `json:"is_dir"`
	Rewrite bool   `json:"rewrite"`
}

func EventRfsGetFile(args RfsGetFileArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest:        args.Dest,
		DataMaxSize: args.DataMaxSize,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.File},
		daction.Get,
		meta,
		opts,
	), nil
}

type RfsCreateFolderArgs struct {
	Path string `json:"path"`

	Dest events.Dest `json:"-"`
}

func EventRfsCreateFolder(args RfsCreateFolderArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest: args.Dest,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Folder},
		daction.Create,
		meta,
		opts,
	), nil
}

type RfsUpdateFolderCacheArgs struct {
	Path       string `json:"path"`
	Full       bool   `json:"full"`
	Deep       int    `json:"deep"`
	ExpandPath bool   `json:"expand_path"`
	Reload     bool   `json:"reload"`

	DataMaxSize int64       `json:"-"`
	Dest        events.Dest `json:"-"`
}

func EventRfsUpdateFolderCache(args RfsUpdateFolderCacheArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest:        args.Dest,
		DataMaxSize: args.DataMaxSize,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Folder},
		daction.List,
		meta,
		opts,
	), nil
}

type RfsGetFolderCacheArgs struct {
	AgentUuid UUID   `json:"agent_uuid"`
	Path      string `json:"path"`
	Id        *int64 `json:"id,omitempty"`
	Deep      int    `json:"deep"`
}

func EventRfsGetFolderCache(args RfsGetFolderCacheArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	return events.NewEvent(
		dkind.UserToService,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Folder},
		daction.List,
		meta,
	), nil
}

type RfsCopyItemArgs struct {
	FromPath string `json:"from_path"`
	ToPath   string `json:"to_path"`

	Dest events.Dest `json:"-"`
}

func EventRfsCopyItem(args RfsCopyItemArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest: args.Dest,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Item},
		daction.Copy,
		meta,
		opts,
	), nil
}

type RfsDeleteItemArgs struct {
	Path string `json:"path"`

	Dest events.Dest `json:"-"`
}

func EventRfsDeleteItem(args RfsDeleteItemArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest: args.Dest,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Item},
		daction.Delete,
		meta,
		opts,
	), nil
}

type RfsGetItemInfoArgs struct {
	Path string `json:"path"`

	Dest events.Dest `json:"-"`
}

func EventRfsGetItemInfo(args RfsGetItemInfoArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest: args.Dest,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Item, dcategory.Info},
		daction.Get,
		meta,
		opts,
	), nil
}

type RfsMoveItemArgs struct {
	FromPath string `json:"from_path"`
	ToPath   string `json:"to_path"`

	Dest events.Dest `json:"-"`
}

func EventRfsMoveItem(args RfsMoveItemArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest: args.Dest,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Item},
		daction.Move,
		meta,
		opts,
	), nil
}

type RfsRenameItemArgs struct {
	FromPath string `json:"from_path"`
	ToPath   string `json:"to_path"`

	Dest events.Dest `json:"-"`
}

func EventRfsRenameItem(args RfsRenameItemArgs) (IEvent, error) {
	meta, err := utils.ConvertTo[map[string]any](args)
	if err != nil {
		return nil, err
	}
	opts := events.NewEventOpts{
		Dest: args.Dest,
	}
	return events.NewEvent(
		dkind.UserToAgent,
		[]Category{dcategory.Agent, dcategory.Rfs, dcategory.Item},
		daction.Rename,
		meta,
		opts,
	), nil
}
