package app

import (
	"agent/client"
	"agent/commons/cross"
	"agent/commons/debug"
	"agent/commons/utime"
	"context"
	"os"
	"os/user"
	"path/filepath"
	"runtime"

	"strings"
)

var startTime = utime.NanoNow()

func NewStartupInfo(ctx context.Context) map[string]any {
	cl := client.ExtractClient(ctx)
	cfg := cl.Config()

	agentName := cfg.Client.Name
	device := deviceInfo()
	created := utime.NanoNow()

	res := map[string]any{
		"process": processInfo(),
		"user":    userInfo(),
		"os":      osInfo(),
		"device":  device,
		"created": created,

		"server": map[string]any{
			"schema": cfg.Server.Schema,
			"host":   cfg.Server.Host,
			"port":   cfg.Server.Port,
		},

		"schedule": cfg.Schedule,
	}

	if len(agentName) > 0 {
		res["name"] = agentName
	}

	//utils.PrintJson(res)

	return res
}

func deviceInfo() map[string]any {
	err := error(nil)

	res := map[string]any{
		"host": deviceHost(),

		"cpu":     cpuInfo(),
		"display": displayInfo(),
	}

	if res["uuid"], err = cross.DeviceUuid(); err != nil {
		debug.LogErr(err)
	}

	return res
}

func deviceHost() map[string]any {
	host, err := os.Hostname()
	if err != nil {
		debug.LogErr(err)
	}
	res := map[string]any{
		"name": host,
	}
	return res
}

func processInfo() map[string]any {
	workDir, err := os.Getwd()
	if err != nil {
		debug.LogErr(err)
	}
	path, err := os.Executable()
	if err != nil {
		debug.LogErr(err)
	}

	res := map[string]any{
		//"env":     processEnv(),
		"cwd":     workDir,
		"pid":     os.Getpid(),
		"path":    filepath.Dir(path),
		"image":   filepath.Base(path),
		"created": startTime,
	}

	// utils.PrintJson(res)

	return res
}

func processEnv() map[string]string {
	res := map[string]string{}
	for _, item := range os.Environ() {
		if vals := strings.SplitN(item, "=", 2); len(vals) > 1 {
			res[vals[0]] = vals[1]
		}
	}
	return res
}

func userInfo() map[string]any {
	user, err := user.Current()
	if err != nil {
		debug.LogErr(err)
	}

	username := ""
	if runtime.GOOS == "windows" {
		username = os.Getenv("USERNAME")
	} else {
		username = user.Username
	}

	res := map[string]any{
		"is_admin": userIsAdmin(),
		"username": username,
		"name":     user.Name,
		"home":     user.HomeDir,
		"uid":      user.Uid,
		"gid":      user.Gid,
	}

	return res
}

func userIsAdmin() bool {
	if runtime.GOOS == "windows" {
		_, err := os.Open("\\\\.\\PHYSICALDRIVE0")
		return err == nil
	}
	return os.Geteuid() == 0
}

func osInfo() map[string]any {
	res := map[string]any{
		"short": runtime.GOOS,
	}
	return res
}

func cpuInfo() map[string]any {
	res := map[string]any{
		"arch":  runtime.GOARCH,
		"count": runtime.NumCPU(),
	}
	return res
}

func displayInfo() map[string]any {
	res := map[string]any{
		"width":  0,
		"height": 0,
	}
	return res
}
