package entity

import (
	"fmt"
	"time"
)

// Block is the aggregate root representing an indexed blockchain block.
type Block struct {
	Height    int64     `json:"height"`
	Hash      string    `json:"hash"`
	Timestamp time.Time `json:"timestamp"`
	TxCount   int       `json:"txCount"`
}

// NewBlock is the factory method that creates a validated Block entity.
func NewBlock(height int64, hash string, timestamp time.Time, txCount int) (*Block, error) {
	if height < 0 {
		return nil, fmt.Errorf("block height must be non-negative, got %d", height)
	}
	if hash == "" {
		return nil, fmt.Errorf("block hash must not be empty")
	}
	if txCount < 0 {
		return nil, fmt.Errorf("transaction count must be non-negative, got %d", txCount)
	}
	return &Block{
		Height:    height,
		Hash:      hash,
		Timestamp: timestamp,
		TxCount:   txCount,
	}, nil
}

// Validate checks all invariants on an existing Block.
func (b *Block) Validate() error {
	if b.Height < 0 {
		return fmt.Errorf("block height must be non-negative")
	}
	if b.Hash == "" {
		return fmt.Errorf("block hash must not be empty")
	}
	if b.TxCount < 0 {
		return fmt.Errorf("transaction count must be non-negative")
	}
	return nil
}

// IsGenesis reports whether this is the genesis block (height 0).
func (b *Block) IsGenesis() bool {
	return b.Height == 0
}

// HasTransactions reports whether this block contains any transactions.
func (b *Block) HasTransactions() bool {
	return b.TxCount > 0
}

// ChainTransaction represents an indexed on-chain transaction.
type ChainTransaction struct {
	Hash        string    `json:"hash"`
	BlockHeight int64     `json:"blockHeight"`
	From        string    `json:"from"`
	To          string    `json:"to"`
	Amount      string    `json:"amount"`
	Status      string    `json:"status"`
	Timestamp   time.Time `json:"timestamp"`
}

// NewChainTransaction is the factory method that creates a validated ChainTransaction.
func NewChainTransaction(hash string, blockHeight int64, from, to, amount, status string, timestamp time.Time) (*ChainTransaction, error) {
	if hash == "" {
		return nil, fmt.Errorf("transaction hash must not be empty")
	}
	if blockHeight < 0 {
		return nil, fmt.Errorf("block height must be non-negative")
	}
	if from == "" {
		return nil, fmt.Errorf("from address must not be empty")
	}
	return &ChainTransaction{
		Hash:        hash,
		BlockHeight: blockHeight,
		From:        from,
		To:          to,
		Amount:      amount,
		Status:      status,
		Timestamp:   timestamp,
	}, nil
}

// Validate checks all invariants on an existing ChainTransaction.
func (tx *ChainTransaction) Validate() error {
	if tx.Hash == "" {
		return fmt.Errorf("transaction hash must not be empty")
	}
	if tx.BlockHeight < 0 {
		return fmt.Errorf("block height must be non-negative")
	}
	if tx.From == "" {
		return fmt.Errorf("from address must not be empty")
	}
	return nil
}

// IsConfirmed reports whether the transaction has a "confirmed" status.
func (tx *ChainTransaction) IsConfirmed() bool {
	return tx.Status == "confirmed"
}

// IsPending reports whether the transaction has a "pending" status.
func (tx *ChainTransaction) IsPending() bool {
	return tx.Status == "pending"
}
