package masque

import (
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"net"
)

type Config struct {
	PrivateKey     string `json:"private_key"`      // Base64-encoded ECDSA private key
	EndpointV4     string `json:"endpoint_v4"`      // IPv4 address of the endpoint
	EndpointV6     string `json:"endpoint_v6"`      // IPv6 address of the endpoint
	EndpointH2V4   string `json:"endpoint_h2_v4"`   // IPv4 address used in HTTP/2 mode
	EndpointH2V6   string `json:"endpoint_h2_v6"`   // IPv6 address used in HTTP/2 mode
	EndpointPubKey string `json:"endpoint_pub_key"` // PEM-encoded ECDSA public key of the endpoint to verify against
	License        string `json:"license"`          // Application license key
	ID             string `json:"id"`               // Device unique identifier
	AccessToken    string `json:"access_token"`     // Authentication token for API access
	IPv4           string `json:"ipv4"`             // Assigned IPv4 address
	IPv6           string `json:"ipv6"`             // Assigned IPv6 address
}

func (c *Config) GetEcPrivateKey() (*ecdsa.PrivateKey, error) {
	privKeyB64, err := base64.StdEncoding.DecodeString(c.PrivateKey)
	if err != nil {
		return nil, fmt.Errorf("failed to decode private key: %v", err)
	}
	privKey, err := x509.ParseECPrivateKey(privKeyB64)
	if err != nil {
		return nil, fmt.Errorf("failed to parse private key: %v", err)
	}
	return privKey, nil
}

func (c *Config) GetEcEndpointPublicKey() (*ecdsa.PublicKey, error) {
	endpointPubKeyB64, _ := pem.Decode([]byte(c.EndpointPubKey))
	if endpointPubKeyB64 == nil {
		return nil, fmt.Errorf("failed to decode endpoint public key")
	}

	pubKey, err := x509.ParsePKIXPublicKey(endpointPubKeyB64.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse public key: %v", err)
	}

	ecPubKey, ok := pubKey.(*ecdsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("failed to assert public key as ECDSA")
	}

	return ecPubKey, nil
}

func (c *Config) SelectEndpointFromConfig(useHTTP2 bool, useIPv6 bool, port int) (net.Addr, error) {
	if useHTTP2 {
		if useIPv6 {
			if c.EndpointH2V6 == "" {
				return nil, fmt.Errorf("--http2 with --ipv6 requires config endpoint_h2_v6 to be set")
			}
			ip := net.ParseIP(c.EndpointH2V6)
			if ip == nil {
				return nil, fmt.Errorf("invalid endpoint_h2_v6 value %q", c.EndpointH2V6)
			}

			return &net.TCPAddr{IP: ip, Port: port}, nil
		}
		v4 := c.EndpointH2V4
		ip := net.ParseIP(v4)
		if ip == nil {
			return nil, fmt.Errorf("invalid endpoint_h2_v4 value %q")
		}
		return &net.TCPAddr{IP: ip, Port: port}, nil
	}
	if useIPv6 {
		ip := net.ParseIP(c.EndpointV6)
		if ip == nil {
			return nil, fmt.Errorf("invalid endpoint_v6 value %q", c.EndpointV6)
		}
		return &net.UDPAddr{IP: ip, Port: port}, nil
	}
	ip := net.ParseIP(c.EndpointV4)
	if ip == nil {
		return nil, fmt.Errorf("invalid endpoint_v4 value %q", c.EndpointV4)
	}
	return &net.UDPAddr{IP: ip, Port: port}, nil
}
