package analytics

import (
	"context"
	"fmt"

	"github.com/jackc/pgx/v5/pgxpool"
)

// Calculator calculates network analytics
type Calculator struct {
	db      *pgxpool.Pool
	chainID int
}

// NewCalculator creates a new analytics calculator
func NewCalculator(db *pgxpool.Pool, chainID int) *Calculator {
	return &Calculator{
		db:      db,
		chainID: chainID,
	}
}

// NetworkStats represents network statistics
type NetworkStats struct {
	CurrentBlock        int64   `json:"current_block"`
	TPS                 float64 `json:"tps"`
	GPS                 float64 `json:"gps"`
	AvgGasPrice         int64   `json:"avg_gas_price"`
	PendingTransactions int     `json:"pending_transactions"`
	BlockTime           float64 `json:"block_time_seconds"`
}

// CalculateNetworkStats calculates current network statistics
func (c *Calculator) CalculateNetworkStats(ctx context.Context) (*NetworkStats, error) {
	// Get current block
	var currentBlock int64
	err := c.db.QueryRow(ctx,
		`SELECT MAX(number) FROM blocks WHERE chain_id = $1`,
		c.chainID,
	).Scan(&currentBlock)
	if err != nil {
		return nil, fmt.Errorf("failed to get current block: %w", err)
	}

	// Get transactions in last 10 blocks
	var txCount int
	var totalGas int64
	var blockTimeSum float64

	query := `
		SELECT 
			COUNT(*) as tx_count,
			SUM(gas_used) as total_gas,
			EXTRACT(EPOCH FROM (MAX(timestamp) - MIN(timestamp))) / COUNT(DISTINCT block_number) as avg_block_time
		FROM transactions
		WHERE chain_id = $1 AND block_number > $2
	`

	err = c.db.QueryRow(ctx, query, c.chainID, currentBlock-10).Scan(&txCount, &totalGas, &blockTimeSum)
	if err != nil {
		txCount = 0
		totalGas = 0
		blockTimeSum = 0
	}

	// Calculate TPS and GPS
	tps := float64(txCount) / (blockTimeSum * 10)
	gps := float64(totalGas) / (blockTimeSum * 10)

	// Get average gas price
	var avgGasPrice int64
	c.db.QueryRow(ctx,
		`SELECT AVG(gas_price) FROM transactions WHERE chain_id = $1 AND block_number > $2 AND gas_price IS NOT NULL`,
		c.chainID, currentBlock-100,
	).Scan(&avgGasPrice)

	// Get pending transactions
	var pendingTx int
	c.db.QueryRow(ctx,
		`SELECT COUNT(*) FROM mempool_transactions WHERE chain_id = $1 AND status = 'pending'`,
		c.chainID,
	).Scan(&pendingTx)

	return &NetworkStats{
		CurrentBlock:        currentBlock,
		TPS:                 tps,
		GPS:                 gps,
		AvgGasPrice:         avgGasPrice,
		PendingTransactions: pendingTx,
		BlockTime:           blockTimeSum,
	}, nil
}

// TopContracts gets top contracts by transaction count
func (c *Calculator) TopContracts(ctx context.Context, limit int) ([]ContractStats, error) {
	query := `
		SELECT 
			to_address as contract_address,
			COUNT(*) as tx_count,
			SUM(value) as total_value
		FROM transactions
		WHERE chain_id = $1 AND to_address IS NOT NULL
		GROUP BY to_address
		ORDER BY tx_count DESC
		LIMIT $2
	`

	rows, err := c.db.Query(ctx, query, c.chainID, limit)
	if err != nil {
		return nil, fmt.Errorf("failed to query top contracts: %w", err)
	}
	defer rows.Close()

	var contracts []ContractStats
	for rows.Next() {
		var contract ContractStats
		if err := rows.Scan(&contract.Address, &contract.TransactionCount, &contract.TotalValue); err != nil {
			continue
		}
		contracts = append(contracts, contract)
	}

	return contracts, nil
}

// ContractStats represents contract statistics
type ContractStats struct {
	Address          string
	TransactionCount int64
	TotalValue       string
}

