package mempool

import (
	"context"
	"database/sql"
	"time"

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

// Tracker tracks pending transactions in the mempool
type Tracker struct {
	db      *pgxpool.Pool
	client  *ethclient.Client
	chainID int
}

// NewTracker creates a new mempool tracker
func NewTracker(db *pgxpool.Pool, client *ethclient.Client, chainID int) *Tracker {
	return &Tracker{
		db:      db,
		client:  client,
		chainID: chainID,
	}
}

// TrackPendingTransaction tracks a pending transaction
func (t *Tracker) TrackPendingTransaction(ctx context.Context, tx *types.Transaction) error {
	from, _ := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)

	var toAddress sql.NullString
	if tx.To() != nil {
		toAddress.String = tx.To().Hex()
		toAddress.Valid = true
	}

	var maxFeePerGas, maxPriorityFeePerGas sql.NullInt64
	if tx.Type() == types.DynamicFeeTxType {
		if tx.GasFeeCap() != nil {
			maxFeePerGas.Int64 = tx.GasFeeCap().Int64()
			maxFeePerGas.Valid = true
		}
		if tx.GasTipCap() != nil {
			maxPriorityFeePerGas.Int64 = tx.GasTipCap().Int64()
			maxPriorityFeePerGas.Valid = true
		}
	}

	query := `
		INSERT INTO mempool_transactions (
			time, chain_id, hash, from_address, to_address, value,
			gas_price, max_fee_per_gas, max_priority_fee_per_gas,
			gas_limit, nonce, input_data_length, first_seen, status
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
		ON CONFLICT (time, chain_id, hash) DO UPDATE SET
			status = $14,
			updated_at = NOW()
	`

	_, err := t.db.Exec(ctx, query,
		time.Now(),
		t.chainID,
		tx.Hash().Hex(),
		from.Hex(),
		toAddress,
		tx.Value().String(),
		tx.GasPrice().Int64(),
		maxFeePerGas,
		maxPriorityFeePerGas,
		tx.Gas(),
		tx.Nonce(),
		len(tx.Data()),
		time.Now(),
		"pending",
	)

	return err
}

// UpdateTransactionStatus updates transaction status when confirmed
func (t *Tracker) UpdateTransactionStatus(ctx context.Context, txHash common.Hash, blockNumber int64, status string) error {
	query := `
		UPDATE mempool_transactions
		SET status = $1, confirmed_block_number = $2, confirmed_at = NOW()
		WHERE chain_id = $3 AND hash = $4
	`

	_, err := t.db.Exec(ctx, query, status, blockNumber, t.chainID, txHash.Hex())
	return err
}

