package consensus

import (
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"math/big"
	"time"

	"dejo_node/internal/transactions"
)

// Finalizer encapsula a lógica de selar e assinar blocos.
type Finalizer struct {
	PrivateKey *ecdsa.PrivateKey
	NodeID     string // opcional: ID do produtor do bloco
}

// Finalize executa a finalização de um bloco:
// - Adiciona timestamp
// - Gera hash final
// - Retorna assinatura
func (f *Finalizer) Finalize(block *transactions.Block) (string, error) {
	if block == nil {
		return "", errors.New("bloco nulo")
	}

	block.Timestamp = time.Now().Unix()

	// Geração do hash usando campos existentes do bloco
	hashInput := []byte(
		fmt.Sprintf("%d|%s|%d|%s",
			block.Index,
			block.PrevHash,
			block.Timestamp,
			f.NodeID,
		),
	)
	hash := sha256.Sum256(hashInput)
	block.Hash = hex.EncodeToString(hash[:])

	r, s, err := ecdsa.Sign(rand.Reader, f.PrivateKey, hash[:])
	if err != nil {
		return "", err
	}

	sig := append(r.Bytes(), s.Bytes()...)
	signature := hex.EncodeToString(sig)

	return signature, nil
}

// VerifySignature verifica se a assinatura é válida com a chave pública fornecida.
func VerifySignature(block *transactions.Block, signature string, pubKey *ecdsa.PublicKey) bool {
	hash, err := hex.DecodeString(block.Hash)
	if err != nil {
		return false
	}

	sig, err := hex.DecodeString(signature)
	if err != nil || len(sig) < 64 {
		return false
	}

	r := big.NewInt(0).SetBytes(sig[:len(sig)/2])
	s := big.NewInt(0).SetBytes(sig[len(sig)/2:])

	return ecdsa.Verify(pubKey, hash, r, s)
}