package api

import (
	"agent/client/events"
	"context"
	"encoding/json"

	"github.com/google/uuid"
)

type RfsStatus uint8

var (
	RfsStatusNone     RfsStatus = 0
	RfsStatusNew      RfsStatus = 1
	RfsStatusComplete RfsStatus = 2
	RfsStatusError    RfsStatus = 3
)

type RfsAction uint8

var (
	RfsActionNone    RfsAction = 0
	RfsActionCreate  RfsAction = 1
	RfsActionCopy    RfsAction = 2
	RfsActionRename  RfsAction = 3
	RfsActionMove    RfsAction = 4
	RfsActionGet     RfsAction = 5
	RfsActionGetInfo RfsAction = 6
	RfsActionList    RfsAction = 7
	RfsActionDelete  RfsAction = 8
	RfsActionReset   RfsAction = 9
)

type RfsType uint8

var (
	RfsTypeNone RfsType = 0
	RfsTypeFile RfsType = 1
	RfsTypeDir  RfsType = 2
)

type RfsActionStatus struct {
	Id int64 `json:"id"`

	AgentUuid        UUID `json:"agent_uuid"`
	VirtualEventUuid UUID `json:"virtual_event_uuid"`

	Path1 string `json:"path1"`
	Path2 string `json:"path2"`

	Params map[string]any `json:"params"`

	Action      RfsAction `json:"action"`
	Status      RfsStatus `json:"status"`
	CreatorUuid UUID      `json:"creator_uuid"`

	Created int64 `json:"created"`
	Updated int64 `json:"updated"`
}

type RfsNode struct {
	Id      int64     `json:"id"`
	Name    string    `json:"name"`
	Dir     string    `json:"dir"`
	Empty   bool      `json:"empty"`
	Loaded  int64     `json:"loaded"`
	Size    int64     `json:"size"`
	Created int64     `json:"created"`
	Updated int64     `json:"updated"`
	IsDir   bool      `json:"is_dir"`
	Childs  []RfsNode `json:"childs"`
}

func RfsReset(ctx context.Context, client IClient,
	agentUuid UUID,
) (err error) {
	event, err := EventRfsReset(agentUuid)
	if err != nil {
		return err
	}
	_, err = client.Execute(ctx, event)
	return err
}

type RfsListActionStatusResult struct {
	NextPage struct {
		Offset int64 `json:"offset"`
		Limit  int64 `json:"limit"`
		Exist  bool  `json:"exist"`
	} `json:"next_page,omitempty"`

	Items []RfsActionStatus `json:"items"`
}

func RfsListActionStatus(ctx context.Context, client IClient,
	args RfsListActionStatusArgs,
) (res RfsListActionStatusResult, err error) {
	event, err := EventRfsListActionStatus(args)
	if err != nil {
		return res, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return res, err
	}
	return res, json.Unmarshal(data, &res)
}

func RfsCreateFile(ctx context.Context, client IClient,
	args RfsCreateFileArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsCreateFile(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsGetFile(ctx context.Context, client IClient,
	args RfsGetFileArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsGetFile(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsCreateFolder(ctx context.Context, client IClient,
	args RfsCreateFolderArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsCreateFolder(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsUpdateFolderCache(ctx context.Context, client IClient,
	args RfsUpdateFolderCacheArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsUpdateFolderCache(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsGetFolderCache(ctx context.Context, client IClient,
	args RfsGetFolderCacheArgs,
	onResult ...events.OnResult,
) (root RfsNode, err error) {
	eventIn, err := EventRfsGetFolderCache(args)
	if err != nil {
		return root, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, eventIn)
	if err != nil {
		return root, err
	}
	if err := json.Unmarshal(data, &root); err != nil {
		return root, err
	}
	return root, nil
}

func RfsCopyItem(ctx context.Context, client IClient,
	args RfsCopyItemArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsCopyItem(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsDeleteItem(ctx context.Context, client IClient,
	args RfsDeleteItemArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsDeleteItem(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsGetItemInfo(ctx context.Context, client IClient,
	args RfsGetItemInfoArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsGetItemInfo(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsMoveItem(ctx context.Context, client IClient,
	args RfsMoveItemArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsMoveItem(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}

func RfsRenameItem(ctx context.Context, client IClient,
	args RfsRenameItemArgs,
	onResult ...events.OnResult,
) (eventUuid UUID, err error) {
	eventIn, err := EventRfsRenameItem(args)
	if err != nil {
		return uuid.Nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return uuid.Nil, err
	}
	if len(onResult) > 0 {
		err = onResult[0](ctx, client, eventIn, eventOut)
	}
	return eventOut.Uuid(), err
}
