package include

import (
	"agent/commons/utime"
	"context"
	"encoding/json"

	"github.com/google/uuid"
)

type LoginResult struct {
	Config map[string]any
	Token  struct {
		Value string
	}
	SrvTime int64
	MaskKey []byte
}

type ClientMethods struct {
	NewStartupInfo     func(ctx context.Context) map[string]any
	Login              func(ctx context.Context, startupInfo map[string]any) (res LoginResult, err error)
	DownloadConfig     func(ctx context.Context) (res map[string]any, err error)
	Ping               func(ctx context.Context) (srvTime int64, err error)
	CheckServiceHealth func(ctx context.Context) error
}

type ClientItenterval struct {
	Ping         int
	Next         int
	Login        int
	ConsoleInput int
}

func (i ClientItenterval) MarshalJSON() ([]byte, error) {
	res := map[string]any{}

	res["ping"] = i.Ping
	res["next"] = i.Next
	res["login"] = i.Login
	res["console_input"] = i.ConsoleInput

	return json.Marshal(res)
}

func (i *ClientItenterval) UnmarshalJSON(data []byte) error {
	jsonData := map[string]any{}
	if err := json.Unmarshal(data, &jsonData); err != nil {
		return err
	}

	if val, ok := jsonData["ping"].(float64); ok {
		i.Ping = int(val)
	}
	if val, ok := jsonData["next"].(float64); ok {
		i.Next = int(val)
	}
	if val, ok := jsonData["login"].(float64); ok {
		i.Login = int(val)
	}
	if val, ok := jsonData["console_input"].(float64); ok {
		i.ConsoleInput = int(val)
	}

	return nil
}

type ClientLoginOpts struct {
	AgentUuid uuid.UUID
	Debug     bool
}

func (l ClientLoginOpts) ToMap() map[string]any {
	res := map[string]any{}

	if l.AgentUuid != uuid.Nil {
		res["agent_uuid"] = l.AgentUuid
	}
	if l.Debug {
		res["debug"] = l.Debug
	}

	return res
}

type AuthDataOpts struct {
	PubKeyTag     bool
	Expired       int64
	TokenValue    string
	RoundToBase64 bool
	ExtraSize     int
	MinTrashSize  int
	MaxTrashSize  int
}

type IClient interface {
	Transport() ITransport
	Methods() ClientMethods

	NewStartupInfo(ctx context.Context) map[string]any

	Config() *AppConfig
	DownloadConfig(ctx context.Context) (err error)
	SetConfig(ctx context.Context, config map[string]any) (err error)

	Schema() string
	Host() string
	Port() int
	Token() string

	Interval() ClientItenterval
	SetInterval(interval ClientItenterval)

	SetMaskKey(maskKey []byte)

	Reset()

	IsAuthorized() bool
	CanLogin() bool

	NextLogin() utime.Duration
	SetNextLogin(interval utime.Duration)

	SetThrottle(to utime.Time)

	AuthData(opts ...AuthDataOpts) ([]byte, error)

	Login(ctx context.Context, startupInfo ...map[string]any) (err error)
	Ping(ctx context.Context) (err error)

	LastLogin() utime.Time
	LastPing() utime.Time

	Execute(ctx context.Context, eventIn IEvent) (eventOut IEvent, err error)
}
