package track2

import (
	"context"
	"fmt"
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/jackc/pgx/v5/pgxpool"
)

// BlockIndexer indexes blocks for Track 2
type BlockIndexer struct {
	db      *pgxpool.Pool
	client  *ethclient.Client
	chainID int
}

// NewBlockIndexer creates a new block indexer
func NewBlockIndexer(db *pgxpool.Pool, client *ethclient.Client, chainID int) *BlockIndexer {
	return &BlockIndexer{
		db:      db,
		client:  client,
		chainID: chainID,
	}
}

// IndexBlock indexes a single block
func (bi *BlockIndexer) IndexBlock(ctx context.Context, blockNumber uint64) error {
	block, err := bi.client.BlockByNumber(ctx, big.NewInt(int64(blockNumber)))
	if err != nil {
		return fmt.Errorf("failed to get block: %w", err)
	}

	// Check if block already indexed
	var exists bool
	checkQuery := `SELECT EXISTS(SELECT 1 FROM blocks WHERE chain_id = $1 AND number = $2)`
	err = bi.db.QueryRow(ctx, checkQuery, bi.chainID, blockNumber).Scan(&exists)
	if err != nil {
		return fmt.Errorf("failed to check block existence: %w", err)
	}

	if exists {
		return nil // Already indexed
	}

	// Insert block
	insertQuery := `
		INSERT INTO blocks (
			chain_id, number, hash, parent_hash, miner, difficulty, total_difficulty,
			size, gas_limit, gas_used, timestamp, transaction_count, base_fee_per_gas
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
		ON CONFLICT (chain_id, number) DO NOTHING
	`

	_, err = bi.db.Exec(ctx, insertQuery,
		bi.chainID,
		block.Number().Int64(),
		block.Hash().Hex(),
		block.ParentHash().Hex(),
		block.Coinbase().Hex(),
		block.Difficulty().String(),
		"0", // total_difficulty
		block.Size(),
		block.GasLimit(),
		block.GasUsed(),
		time.Unix(int64(block.Time()), 0),
		len(block.Transactions()),
		block.BaseFee(),
	)

	if err != nil {
		return fmt.Errorf("failed to insert block: %w", err)
	}

	return nil
}

// IndexLatestBlocks indexes the latest N blocks
func (bi *BlockIndexer) IndexLatestBlocks(ctx context.Context, count int) error {
	header, err := bi.client.HeaderByNumber(ctx, nil)
	if err != nil {
		return fmt.Errorf("failed to get latest header: %w", err)
	}

	latestBlock := header.Number.Uint64()

	for i := 0; i < count && latestBlock-uint64(i) >= 0; i++ {
		blockNum := latestBlock - uint64(i)
		if err := bi.IndexBlock(ctx, blockNum); err != nil {
			// Log error but continue
			fmt.Printf("Failed to index block %d: %v\n", blockNum, err)
		}
	}

	return nil
}
