package node

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	mathrand "math/rand"
	"net"
	"os"
	"path/filepath"
	"time"

	"github.com/DeBrosOfficial/network/pkg/config"
	"github.com/DeBrosOfficial/network/pkg/encryption"
	"github.com/multiformats/go-multiaddr"
)

func extractIPFromMultiaddr(multiaddrStr string) string {
	ma, err := multiaddr.NewMultiaddr(multiaddrStr)
	if err != nil {
		return ""
	}

	var ip string
	var dnsName string
	multiaddr.ForEach(ma, func(c multiaddr.Component) bool {
		switch c.Protocol().Code {
		case multiaddr.P_IP4, multiaddr.P_IP6:
			ip = c.Value()
			return false
		case multiaddr.P_DNS4, multiaddr.P_DNS6, multiaddr.P_DNSADDR:
			dnsName = c.Value()
		}
		return true
	})

	if ip != "" {
		return ip
	}

	if dnsName != "" {
		if resolvedIPs, err := net.LookupIP(dnsName); err == nil && len(resolvedIPs) > 0 {
			for _, resolvedIP := range resolvedIPs {
				if resolvedIP.To4() != nil {
					return resolvedIP.String()
				}
			}
			return resolvedIPs[0].String()
		}
	}

	return ""
}

func calculateNextBackoff(current time.Duration) time.Duration {
	next := time.Duration(float64(current) * 1.5)
	maxInterval := 10 * time.Minute
	if next > maxInterval {
		next = maxInterval
	}
	return next
}

func addJitter(interval time.Duration) time.Duration {
	jitterPercent := 0.2
	jitterRange := float64(interval) * jitterPercent
	jitter := (mathrand.Float64() - 0.5) * 2 * jitterRange
	result := time.Duration(float64(interval) + jitter)
	if result < time.Second {
		result = time.Second
	}
	return result
}

func loadNodePeerIDFromIdentity(dataDir string) string {
	expanded, err := config.ExpandPath(dataDir)
	if err != nil {
		return ""
	}
	identityFile := filepath.Join(expanded, "identity.key")

	if info, err := encryption.LoadIdentity(identityFile); err == nil {
		return info.PeerID.String()
	}
	return ""
}

func extractPEMFromTLSCert(tlsCert *tls.Certificate, certPath, keyPath string) error {
	if tlsCert == nil || len(tlsCert.Certificate) == 0 {
		return fmt.Errorf("invalid tls certificate")
	}

	certFile, err := os.Create(certPath)
	if err != nil {
		return err
	}
	defer certFile.Close()

	for _, certBytes := range tlsCert.Certificate {
		if err := pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}); err != nil {
			return fmt.Errorf("failed to encode certificate PEM: %w", err)
		}
	}

	if tlsCert.PrivateKey == nil {
		return fmt.Errorf("private key is nil")
	}

	keyFile, err := os.Create(keyPath)
	if err != nil {
		return err
	}
	defer keyFile.Close()

	keyBytes, err := x509.MarshalPKCS8PrivateKey(tlsCert.PrivateKey)
	if err != nil {
		return fmt.Errorf("failed to marshal private key: %w", err)
	}

	if err := pem.Encode(keyFile, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}); err != nil {
		return fmt.Errorf("failed to encode private key PEM: %w", err)
	}
	if err := os.Chmod(certPath, 0644); err != nil {
		return fmt.Errorf("failed to set certificate permissions: %w", err)
	}
	if err := os.Chmod(keyPath, 0600); err != nil {
		return fmt.Errorf("failed to set private key permissions: %w", err)
	}
	return nil
}

