package api

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

type TunnelOpenPortArgs struct {
	AgentUuid UUID   `json:"agent_uuid"`
	Host      string `json:"host,omitempty"`
	Port      int    `json:"port"`
	Encrypt   *bool  `json:"encrypt,omitempty"`
	SrvPort   int    `json:"srv_port,omitempty"`
	RHost     string `json:"rhost"`
	RPort     int    `json:"rport"`
	Note      string `json:"note,omitempty"`
}

func EventTunnelOpenPort(args TunnelOpenPortArgs) (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.Tunnel, dcategory.Port},
		daction.Open,
		meta,
	), nil
}

type TunnelListenPortArgs struct {
	AgentUuid UUID   `json:"agent_uuid"`
	Port      int    `json:"port"`
	Host      string `json:"host,omitempty"`
	RHost     string `json:"rhost,omitempty"`
	RPort     int    `json:"rport,omitempty"`
	Note      string `json:"note,omitempty"`
}

func EventTunnelListenPort(args TunnelListenPortArgs) (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.Tunnel, dcategory.Port},
		daction.Listen,
		meta,
	), nil
}

type TunnelClosePortArgs struct {
	PortUuids []UUID `json:"port_uuids"`
}

func EventTunnelClosePort(args TunnelClosePortArgs) (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.Tunnel, dcategory.Port},
		daction.Close,
		meta,
	), nil
}

type TunnelGetPortArgs struct {
	PortUuid UUID `json:"port_uuid"`
	SrvPort  int  `json:"srv_port"`
}

func EventTunnelGetPort(args TunnelGetPortArgs) (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.Tunnel, dcategory.Port},
		daction.Get,
		meta,
	), nil
}

type TunnelListPortsArgs struct {
	Kind    string                    `json:"kind"`
	Filter  TunnelListPortsFilterOpts `json:"filter,omitempty"`
	Offset  int64                     `json:"offset,omitempty"`
	Limit   int64                     `json:"limit,omitempty"`
	Reverse bool                      `json:"reverse,omitempty"`
}

type TunnelListPortsFilterOpts struct {
	AgentUuid UUID `json:"agent_uuid,omitempty"`
}

func EventTunnelListPorts(args TunnelListPortsArgs) (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.Tunnel, dcategory.Port},
		daction.List,
		meta,
	), nil
}

type TunnelListPortsByAgentArgs struct {
	AgentUuid UUID  `json:"agent_uuid"`
	Offset    int64 `json:"offset,omitempty"`
	Limit     int64 `json:"limit,omitempty"`
	Reverse   bool  `json:"reverse,omitempty"`
}

func EventTunnelListPortsByAgent(args TunnelListPortsByAgentArgs) (IEvent, error) {
	listArgs := TunnelListPortsArgs{
		Kind: "by_agent",
		Filter: TunnelListPortsFilterOpts{
			AgentUuid: args.AgentUuid,
		},
		Offset:  args.Offset,
		Limit:   args.Limit,
		Reverse: args.Reverse,
	}
	return EventTunnelListPorts(listArgs)
}

type TunnelListPortsAllArgs struct {
	Offset  int64 `json:"offset,omitempty"`
	Limit   int64 `json:"limit,omitempty"`
	Reverse bool  `json:"reverse,omitempty"`
}

func EventTunnelListPortsAll(args TunnelListPortsAllArgs) (IEvent, error) {
	listArgs := TunnelListPortsArgs{
		Kind:    "all",
		Offset:  args.Offset,
		Limit:   args.Limit,
		Reverse: args.Reverse,
	}
	return EventTunnelListPorts(listArgs)
}

type TunnelUpdatePortArgs struct {
	PortUuid UUID   `json:"port_uuid"`
	Note     string `json:"note,omitempty"`
}

func EventTunnelUpdatePort(args TunnelUpdatePortArgs) (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.Tunnel, dcategory.Port},
		daction.Update,
		meta,
	), nil
}
