package api

import (
	"agent/client/events"
	"agent/commons/adata"
	"context"
	"encoding/json"
)

type LfsNode struct {
	Uuid    UUID      `json:"uuid"`
	Name    string    `json:"name"`
	Dir     string    `json:"dir"`
	Size    int64     `json:"size"`
	Created int64     `json:"created"`
	Updated int64     `json:"updated"`
	IsDir   bool      `json:"is_dir"`
	Childs  []LfsNode `json:"childs"`
}

func LfsReset(ctx context.Context, client IClient, agentUuid UUID) error {
	event, err := EventLfsReset(agentUuid)
	if err != nil {
		return err
	}
	_, err = events.ExecuteAndGetData(ctx, client, event)
	return err
}

type LfsItemShort struct {
	Uuid UUID `json:"uuid"`
}

type LfsOwnerType = events.EventOwnerType
type LfsItemType uint8

var (
	LfsItemTypeNone LfsItemType = 0
	LfsItemTypeFile LfsItemType = 1
	LfsItemTypeDir  LfsItemType = 2
)

type LfsItem struct {
	Id       int64 `json:"id"`
	ParentId int64 `json:"parent_id"`

	AgentUuid   UUID `json:"agent_uuid"`
	VirtualUuid UUID `json:"virtual_uuid"`
	DataUuid    UUID `json:"data_uuid"`

	OwnerUuid UUID         `json:"owner_uuid"`
	OwnerType LfsOwnerType `json:"owner_type"`

	NameId int64  `json:"name_id"`
	Name   string `json:"name"`

	ShadowNameId int64  `json:"shadow_name_id"`
	ShadowName   string `json:"shadow_name"`

	Size int64       `json:"size"`
	Type LfsItemType `json:"type"`

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

func LfsCreateFile(ctx context.Context, client IClient,
	args LfsCreateFileArgs,
) (res UUID, err error) {
	event, err := EventLfsCreateFile(args)
	if err != nil {
		return res, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return res, err
	}
	return lfsItemUuidFromResult(data)
}

func LfsGetFile(ctx context.Context, client IClient,
	args LfsGetFileArgs,
) (data adata.IData, err error) {
	eventIn, err := EventLfsGetFile(args)
	if err != nil {
		return nil, err
	}
	eventOut, err := client.Execute(ctx, eventIn)
	if err != nil {
		return nil, err
	}
	return eventOut.Data(), nil
}

func LfsCreateFolder(ctx context.Context, client IClient,
	args LfsCreateFolderArgs,
) (res UUID, err error) {
	event, err := EventLfsCreateFolder(args)
	if err != nil {
		return res, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return res, err
	}
	return lfsItemUuidFromResult(data)
}

func LfsListFolder(ctx context.Context, client IClient,
	args LfsListFolderArgs,
) (nodes LfsNode, err error) {
	event, err := EventLfsListFolder(args)
	if err != nil {
		return nodes, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return nodes, err
	}
	if err := json.Unmarshal(data, &nodes); err != nil {
		return nodes, err
	}
	return nodes, nil
}

func LfsDeleteItem(ctx context.Context, client IClient,
	args LfsDeleteItemArgs,
) error {
	event, err := EventLfsDeleteItem(args)
	if err != nil {
		return err
	}
	_, err = events.ExecuteAndGetData(ctx, client, event)
	return err
}

func LfsGetItemInfo(ctx context.Context, client IClient,
	args LfsGetItemInfoArgs,
) (item LfsItem, err error) {
	event, err := EventLfsGetItemInfo(args)
	if err != nil {
		return item, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return item, err
	}
	if err := json.Unmarshal(data, &item); err != nil {
		return item, err
	}
	return item, nil
}

func LfsGetItemPath(ctx context.Context, client IClient,
	args LfsGetItemPathArgs,
) (path string, err error) {
	event, err := EventLfsGetItemPath(args)
	if err != nil {
		return path, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return path, err
	}
	return string(data), nil
}

func LfsMoveItem(ctx context.Context, client IClient,
	args LfsMoveItemArgs,
) (item LfsItem, err error) {
	event, err := EventLfsMoveItem(args)
	if err != nil {
		return item, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return item, err
	}
	if err := json.Unmarshal(data, &item); err != nil {
		return item, err
	}
	return item, nil
}

func LfsRenameItem(ctx context.Context, client IClient,
	args LfsRenameItemArgs,
) (item LfsItem, err error) {
	event, err := EventLfsRenameItem(args)
	if err != nil {
		return item, err
	}
	data, err := events.ExecuteAndGetData(ctx, client, event)
	if err != nil {
		return item, err
	}
	if err := json.Unmarshal(data, &item); err != nil {
		return item, err
	}
	return item, nil
}

func lfsItemUuidFromResult(data []byte) (res UUID, err error) {
	var item LfsItemShort
	if err := json.Unmarshal(data, &item); err != nil {
		return res, err
	}
	return item.Uuid, nil
}
