package comms

import (
	"encoding/gob"
	"os"
	"os/user"
	"runtime"
	"time"
)

const PROTOCOL_VERSION = 5

// for testing protocol version mismatch we define a separate protocol version
// for the agent and server
var agentProtocolVersion = PROTOCOL_VERSION
var serverProtocolVersion = PROTOCOL_VERSION

func init() {
	RegisterEventsWithGob()
}

// Agent to server events

type EnvironmentInfo struct {
	Username string
	Hostname string
	Pwd      string
	OS       string
	Shell    string
}

type ClientInfo struct {
	ClientId string
}

type SessionInfo struct {
	ClientId string

	// "ssh", "sftp"
	SessionType string
}

type ExpiryTimeUpdate struct {
	ExpiryTime time.Time
}

type HeartBeat struct {
	// Empty
}

type ProtocolVersion struct {
	Version int
}

// initialization mesaage when agent connects to server

type ServerInfo struct {
	// used for testing only.
	TestId int
}

// confirmation message when agent connects
type AgentRegistration struct {
	Ok      bool
	Message string
	// final Id assigned by the server. Usually identical to the requested id
	// but if there is a conflict, a new id is chosen.
	Id             string
	HostPrivateKey []byte
}

// Generic wrapper message required to send messages of arbitrary type

type ConvergeMessage struct {
	Value any
}

func NewEnvironmentInfo(shell string) EnvironmentInfo {
	username, _ := user.Current()
	host, _ := os.Hostname()
	pwd, _ := os.Getwd()
	return EnvironmentInfo{
		Username: username.Username,
		Hostname: host,
		Pwd:      pwd,
		OS:       runtime.GOOS,
		Shell:    shell,
	}
}

func NewSessionInfo(clientId, sessionType string) SessionInfo {
	return SessionInfo{
		ClientId:    clientId,
		SessionType: sessionType,
	}
}

func NewExpiryTimeUpdate(expiryTime time.Time) ExpiryTimeUpdate {
	return ExpiryTimeUpdate{ExpiryTime: expiryTime}
}

func RegisterEventsWithGob() {
	// Agent to ConvergeServer
	gob.Register(EnvironmentInfo{})
	gob.Register(SessionInfo{})
	gob.Register(ExpiryTimeUpdate{})
	gob.Register(HeartBeat{})

	// ConvergeServer to Agent and client
	gob.Register(ProtocolVersion{})

	// ConvergeServer to Client
	gob.Register(ClientConnectionInfo{})

	// Wrapper event.
	gob.Register(ConvergeMessage{})
}

// Server to client events

type ClientConnectionInfo struct {
	Ok      bool
	Message string
}