package p2p

import (
	"crypto/rand"
	"fmt"
	"log"

	"github.com/libp2p/go-libp2p"
	crypto "github.com/libp2p/go-libp2p/core/crypto"
	hostlib "github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/core/network"
	"github.com/libp2p/go-libp2p/core/peer"
	ma "github.com/multiformats/go-multiaddr"
)

// NewSecureHost cria um nó P2P com proteção básica anti-Sybil/DDoS
func NewSecureHost(port int) (hostlib.Host, error) {
	// Gera par de chaves (identidade)
	priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader)
	if err != nil {
		return nil, fmt.Errorf("falha ao gerar chave: %v", err)
	}

	pid, err := peer.IDFromPublicKey(pub)
	if err != nil {
		return nil, fmt.Errorf("erro ao obter PeerID: %v", err)
	}

	addr, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port))
	h, err := libp2p.New(
		libp2p.ListenAddrs(addr),
		libp2p.Identity(priv),
	)
	if err != nil {
		return nil, fmt.Errorf("erro ao criar host libp2p: %v", err)
	}

	log.Printf("✅ Host P2P criado: %s (%s)\n", pid.String(), addr)

	// Proteção: loga e valida conexões
	h.Network().Notify(&connLogger{})

	return h, nil
}

// connLogger registra e controla conexões suspeitas
type connLogger struct{}

func (c *connLogger) Connected(n network.Network, conn network.Conn) {
	if err := LimitConnections(conn); err != nil {
		log.Printf("🚫 Conexão rejeitada: %s (%v)", conn.RemotePeer(), err)
		conn.Close()
		return
	}
	log.Printf("🔗 Peer conectado: %s (%s)", conn.RemotePeer(), conn.RemoteMultiaddr())
}

func (c *connLogger) Disconnected(n network.Network, conn network.Conn) {
	log.Printf("❌ Peer desconectado: %s", conn.RemotePeer())
	ClearConnection(conn)
}

func (c *connLogger) OpenedStream(n network.Network, s network.Stream)      {}
func (c *connLogger) ClosedStream(n network.Network, s network.Stream)      {}
func (c *connLogger) Listen(n network.Network, addr ma.Multiaddr)           {}
func (c *connLogger) ListenClose(n network.Network, addr ma.Multiaddr)      {}