package datavisor

import (
    "encoding/hex"
    "encoding/json"
    "errors"
    "os"

    "ripple/helpers"
)

var errInvalidConfigFile = errors.New("invalid config file")

type (
    PortNumber     int
    Username       string
    ServerAddress  string
    SecretKey      [32]byte
)

type configJSON struct {
    Port          PortNumber    `json:"port"`
    Username      Username      `json:"username"`
    ServerAddress ServerAddress `json:"serverAddress"`
    SecretKey     SecretKey     `json:"secretKey"`
}

func (sa *ServerAddress) UnmarshalJSON(b []byte) error {
    var raw string
    if err := json.Unmarshal(b, &raw); err != nil {
        return err
    }
    if len(raw) > 32 {
        return errInvalidConfigFile
    }
    *sa = ServerAddress(raw)
    return nil
}

func (pn *PortNumber) UnmarshalJSON(b []byte) error {
    var n int
    if err := json.Unmarshal(b, &n); err != nil {
        return err
    }
    if n < 1 || n > 65535 {
        return errInvalidConfigFile
    }
    *pn = PortNumber(n)
    return nil
}

func (u *Username) UnmarshalJSON(b []byte) error {
    var raw string
    if err := json.Unmarshal(b, &raw); err != nil {
        return err
    }
    if !helpers.UsernameRegex.MatchString(raw) {
        return errInvalidConfigFile
    }
    *u = Username(raw)
    return nil
}

func (sk *SecretKey) UnmarshalJSON(b []byte) error {
    var raw string
    if err := json.Unmarshal(b, &raw); err != nil {
        return err
    }
    decoded, err := hex.DecodeString(raw)
    if err != nil || len(decoded) != 32 {
        return errInvalidConfigFile
    }
    copy(sk[:], decoded)
    return nil
}

func (cfg *configJSON) validateAddress() error {
    return helpers.ValidateAddress(string(cfg.ServerAddress), int(cfg.Port))
}

func loadConfigFile(filePath string) (*configJSON, error) {
    data, err := os.ReadFile(filePath)
    if err != nil {
        return nil, err
    }
    var cfg configJSON
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, err
    }
	if err := cfg.validateAddress(); err != nil {
		return nil, err
	}
    return &cfg, nil
}