package peer

import (
	"encoding/json"
	"log"
	"os"
	"path/filepath"
	"vppn/m"
)

type LocalConfig struct {
	LocalPeerIP byte
	Network     []byte
	PubKey      []byte
	PrivKey     []byte
	PubSignKey  []byte
	PrivSignKey []byte
}

type startupCount struct {
	Count uint16
}

func configDir(netName string) string {
	d, err := os.UserHomeDir()
	if err != nil {
		log.Fatalf("Failed to get user home directory: %v", err)
	}
	return filepath.Join(d, ".vppn", netName)
}

func lockFilePath(netName string) string {
	return filepath.Join(configDir(netName), "__lock__")
}

func peerConfigPath(netName string) string {
	return filepath.Join(configDir(netName), "config.json")
}

func peerStatePath(netName string) string {
	return filepath.Join(configDir(netName), "state.json")
}

func startupCountPath(netName string) string {
	return filepath.Join(configDir(netName), "startup_count.json")
}

func statusSocketPath(netName string) string {
	return filepath.Join(configDir(netName), "status.sock")
}

func storeJson(x any, outPath string) error {
	outDir := filepath.Dir(outPath)
	_ = os.MkdirAll(outDir, 0700)

	tmpPath := outPath + ".tmp"
	buf, err := json.Marshal(x)
	if err != nil {
		return err
	}

	f, err := os.Create(tmpPath)
	if err != nil {
		return err
	}

	if _, err := f.Write(buf); err != nil {
		f.Close()
		return err
	}

	if err := f.Sync(); err != nil {
		f.Close()
		return err
	}

	if err := f.Close(); err != nil {
		return err
	}

	return os.Rename(tmpPath, outPath)
}

func storePeerConfig(netName string, pc LocalConfig) error {
	return storeJson(pc, peerConfigPath(netName))
}

func storeNetworkState(netName string, ps m.NetworkState) error {
	return storeJson(ps, peerStatePath(netName))
}

func loadJson(dataPath string, ptr any) error {
	data, err := os.ReadFile(dataPath)
	if err != nil {
		return err
	}

	return json.Unmarshal(data, ptr)
}

func loadPeerConfig(netName string) (pc LocalConfig, err error) {
	return pc, loadJson(peerConfigPath(netName), &pc)
}

func loadNetworkState(netName string) (ps m.NetworkState, err error) {
	return ps, loadJson(peerStatePath(netName), &ps)
}

func loadStartupCount(netName string) (c startupCount, err error) {
	return c, loadJson(startupCountPath(netName), &c)
}

func storeStartupCount(netName string, c startupCount) error {
	return storeJson(c, startupCountPath(netName))
}
