package utils

import (
	"agent/client"
	"agent/client/cmds"
	"agent/client/events"
	"agent/commons/adata"
	"agent/commons/debug"
	"agent/commons/vars"
	"agent/defines/derrs"
	"agent/defines/devent/dtype"
	"agent/modules/commands/api"
	"context"
)

type ResultEventItem struct {
	EventIn  events.RawEvent
	EventOut events.IEvent
}

var DefaultLoginInterval = vars.DefaultLoginInterval
var ForceNextEventInterval = vars.ForceNextEventInterval
var DefaultNextEventInterval = vars.ForceNextEventInterval

func Execute(ctx context.Context, eventIn events.IEvent) (eventOut events.IEvent, errEvent events.IEvent) {
	commandManager := cmds.ExtractCommandManager(ctx)
	if eventOut, err := commandManager.Execute(ctx, eventIn); err != nil {
		return nil, CreateErr(eventIn, err)
	} else if eventOut == nil {
		return events.NewResultEvent(eventIn, dtype.Result), nil
	} else {
		return eventOut, nil
	}
}

func SetResults(ctx context.Context, client client.IClient, results []ResultEventItem) {
	for _, item := range results {
		if _, err := client.Execute(ctx, item.EventOut); err != nil {
			debug.Logf(
				"Error while processing event:\n- UUID: %s\n- Kind: %d\n- Category: %v\n- Action: %d\n- Msg: %s\n\n",
				item.EventIn.VirtualUuid, item.EventIn.Kind, item.EventIn.Category, item.EventIn.Action, err,
			)
			// При отправке ивентов содержащих данные в виде файла, может возникнуть ситуация, что файл не найден или
			// недоступен. В этом случае отправляем событие об ошибке при выполнении события
			if derrs.Contains(err, derrs.CodeDataNotFound) {
				eventOut := events.NewResultEvent2(&item.EventIn, dtype.ResultError, events.NewResultEventOpts{
					ErrData: err.Error(),
				})
				if _, err2 := client.Execute(ctx, eventOut); err2 != nil {
					debug.Logf(
						"Error while sending error event:\n- UUID: %s\n- Kind: %d\n- Category: %v\n- Action: %d\n- Msg: %s\n\n",
						item.EventIn.VirtualUuid, item.EventIn.Kind, item.EventIn.Category, item.EventIn.Action, err2,
					)
				}
			}
		}
	}
}

func RawToEvent(ctx context.Context, rawEvent *events.RawEvent) (event events.IEvent, errEvent events.IEvent) {
	debug.Logf(
		"Event, Kind: %d, Category: %v, Action: %d\n",
		rawEvent.Kind, rawEvent.Category, rawEvent.Action,
	)

	var data adata.IData
	var err error

	if rawEvent.DataSize > 0 && len(rawEvent.Data) == 0 {
		cl := client.ExtractClient(ctx)
		if data, err = api.AgentRequestEventData(ctx, cl, rawEvent.VirtualUuid); err != nil {
			return nil, CreateErr2(rawEvent, err)
		}
	}

	if event, err = events.NewEvent2(rawEvent, data); err != nil {
		return nil, CreateErr2(rawEvent, err)
	}

	return event, nil
}

func CreateErr(event events.IEvent, err error) events.IEvent {
	debug.Log(err)
	return events.NewResultEvent(event, dtype.ResultError, events.NewResultEventOpts{
		ErrData: err.Error(),
	})
}

func CreateErr2(event *events.RawEvent, err error) events.IEvent {
	debug.Log(err)
	return events.NewResultEvent2(event, dtype.ResultError, events.NewResultEventOpts{
		ErrData: err.Error(),
	})
}
