package miner

import (
	"dejo_node/internal/consensus"
	"dejo_node/internal/storage"
	"dejo_node/internal/transactions"
	"dejo_node/internal/ws"
	"fmt"
	"time"
)

// Miner representa o componente responsável por propor blocos válidos.
type Miner struct {
	Engine     consensus.Engine
	BlockStore *storage.BlockStore
	Mempool    *transactions.Mempool
}

// New cria uma nova instância de minerador
func New(engine consensus.Engine, store *storage.BlockStore, mempool *transactions.Mempool) *Miner {
	return &Miner{
		Engine:     engine,
		BlockStore: store,
		Mempool:    mempool,
	}
}

// MineNextBlock propõe, valida e armazena um novo bloco se possível
func (m *Miner) MineNextBlock() (*transactions.Block, error) {
	if !m.Engine.CanPropose() {
		return nil, fmt.Errorf("este nó não tem permissão para propor blocos")
	}

	txns := m.Mempool.Pending()
	if len(txns) == 0 {
		return nil, fmt.Errorf("nenhuma transação pendente para minerar")
	}

	lastBlock, err := m.BlockStore.GetLatestBlock()
	index := uint64(0)
	prevHash := ""
	if err == nil {
		index = lastBlock.Index + 1
		prevHash = lastBlock.Hash
	}

	blk := &transactions.Block{
		Index:    index,
		Timestamp: time.Now().Unix(),
		PrevHash: prevHash,
		Txns:     txns,
	}
	blk.ComputeHash()

	if err := m.Engine.Finalize(blk); err != nil {
		return nil, fmt.Errorf("bloco rejeitado pelo consenso: %w", err)
	}

	if err := m.BlockStore.SaveBlock(blk); err != nil {
		return nil, fmt.Errorf("erro ao salvar bloco: %w", err)
	}

	// Emitir eventos WebSocket
	ws.Emit("newBlock", map[string]any{
		"index": blk.Index,
		"hash":  blk.Hash,
	})
	for _, tx := range blk.Txns {
		ws.Emit("txConfirmed", map[string]any{
			"hash": tx.Hash(),
		})
	}

	m.Mempool.Clear()
	return blk, nil
}