package cmds

import (
	"agent/client"
	"agent/client/events"
	"agent/commons/debug"
	"agent/defines/dcmds"
	"agent/defines/derrs"
	"agent/defines/devent/daction"
	"agent/defines/devent/dcategory"
	"agent/defines/devent/dtype"
	"agent/modules/ports/api"
	"agent/modules/ports/internal"
	"context"
	"encoding/json"
	"errors"
)

type PortOpenCmd struct {
	dcmds.ServiceToAgentCmd
}

func (c *PortOpenCmd) Category() []Category {
	return []Category{dcategory.Agent, dcategory.Tunnel, dcategory.Port}
}

func (c *PortOpenCmd) Action() Action {
	return daction.Open
}

func (c *PortOpenCmd) Execute(ctx context.Context, eventIn IEvent) (eventOut IEvent, err error) {
	debug.Logf("PortOpenCmd")

	data, err := eventIn.Data2()
	if err != nil {
		return nil, errors.Join(err, derrs.NewDataNotFoundError())
	}

	debug.Logf("Params: %s", string(data))

	var params api.PortParams
	if err = json.Unmarshal(data, &params); err != nil {
		return nil, errors.Join(err, derrs.NewUnknownError())
	}

	cl := client.ExtractClient(ctx)
	tunPort, err := internal.NewTunnelPortOpen(cl, params)
	if err != nil {
		return nil, errors.Join(err, derrs.NewUnknownError())
	}
	params = tunPort.Params()

	go tunPort.Run(ctx)

	return events.NewResultEvent(eventIn, dtype.Result, events.NewResultEventOpts{
		Meta: map[string]any{
			"host": params.Host,
			"port": params.Port,

			"link_to": map[string]any{
				"host": params.LinkTo.Host,
				"port": params.LinkTo.Port,
			},
		},
	}), nil
}
