package tron

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

	"github.com/ethereum/go-ethereum/core/types"
	troncore "github.com/fbsobreira/gotron-sdk/pkg/proto/core"
	"github.com/tech/sendico/gateway/tron/internal/service/gateway/tronclient"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/mlogger"
	"go.uber.org/zap"
)

const (
	// Default poll interval for confirmation checking
	defaultPollInterval = 3 * time.Second
)

// AwaitConfirmationNative waits for transaction confirmation using native TRON gRPC.
func AwaitConfirmationNative(
	ctx context.Context,
	logger mlogger.Logger,
	tronClient *tronclient.Client,
	txHash string,
) (*types.Receipt, error) {
	if tronClient == nil {
		return nil, merrors.Internal("tron driver: tron client not initialized")
	}

	normalizedHash := normalizeTxHash(txHash)
	if normalizedHash == "" {
		logger.Warn("Missing transaction hash for confirmation")
		return nil, merrors.InvalidArgument("tron driver: tx hash is required")
	}

	logger.Debug("Awaiting native TRON confirmation",
		zap.String("tx_hash", normalizedHash),
	)

	ticker := time.NewTicker(defaultPollInterval)
	defer ticker.Stop()

	for {
		txInfo, err := tronClient.GetTransactionInfoByID(normalizedHash)
		if err != nil {
			// Not found yet, continue polling
			logger.Debug("Transaction not yet confirmed",
				zap.String("tx_hash", normalizedHash),
				zap.Error(err),
			)
		} else if txInfo != nil && txInfo.BlockNumber > 0 {
			// Transaction is confirmed
			receipt := convertTronInfoToReceipt(txInfo)
			logger.Info("Native TRON transaction confirmed",
				zap.String("tx_hash", normalizedHash),
				zap.Int64("block_number", txInfo.BlockNumber),
				zap.Uint64("status", receipt.Status),
				zap.Int64("fee", txInfo.Fee),
			)
			return receipt, nil
		}

		select {
		case <-ticker.C:
			continue
		case <-ctx.Done():
			logger.Warn("Context cancelled while awaiting TRON confirmation",
				zap.String("tx_hash", normalizedHash),
			)
			return nil, ctx.Err()
		}
	}
}

// convertTronInfoToReceipt converts TRON TransactionInfo to go-ethereum Receipt for compatibility.
func convertTronInfoToReceipt(txInfo *troncore.TransactionInfo) *types.Receipt {
	if txInfo == nil {
		return nil
	}

	// Determine status: TRON uses 0 = SUCCESS, 1 = FAILED
	// go-ethereum uses 1 = success, 0 = failure
	var status uint64
	if txInfo.Result == troncore.TransactionInfo_SUCESS {
		status = 1 // Success
	} else {
		status = 0 // Failed
	}

	// Create a receipt that's compatible with the existing codebase
	gasUsed := uint64(0)
	if txInfo.Fee > 0 {
		gasUsed = uint64(txInfo.Fee)
	}
	receipt := &types.Receipt{
		Status:      status,
		BlockNumber: big.NewInt(txInfo.BlockNumber),
		// TRON fees are in SUN, but we store as-is for logging
		GasUsed: gasUsed,
	}

	// Set transaction hash from txInfo.Id
	if len(txInfo.Id) == 32 {
		var txHash [32]byte
		copy(txHash[:], txInfo.Id)
		receipt.TxHash = txHash
	}

	// Set contract address if available
	if len(txInfo.ContractAddress) > 0 {
		var contractAddr [20]byte
		// TRON addresses are 21 bytes with 0x41 prefix, take last 20
		if len(txInfo.ContractAddress) == 21 {
			copy(contractAddr[:], txInfo.ContractAddress[1:])
		} else if len(txInfo.ContractAddress) == 20 {
			copy(contractAddr[:], txInfo.ContractAddress)
		}
		receipt.ContractAddress = contractAddr
	}

	return receipt
}

// GetTransactionStatus checks the current status of a TRON transaction.
// Returns:
//   - 1 if confirmed and successful
//   - 0 if confirmed but failed
//   - -1 if not yet confirmed (pending)
func GetTransactionStatus(
	ctx context.Context,
	logger mlogger.Logger,
	tronClient *tronclient.Client,
	txHash string,
) (int, error) {
	if tronClient == nil {
		return -1, merrors.Internal("tron driver: tron client not initialized")
	}

	normalizedHash := normalizeTxHash(txHash)
	if normalizedHash == "" {
		return -1, merrors.InvalidArgument("tron driver: tx hash is required")
	}

	txInfo, err := tronClient.GetTransactionInfoByID(normalizedHash)
	if err != nil {
		return -1, err
	}

	if txInfo == nil || txInfo.BlockNumber == 0 {
		// Not yet confirmed
		return -1, nil
	}

	// Confirmed - check result
	if txInfo.Result == troncore.TransactionInfo_SUCESS {
		return 1, nil
	}
	return 0, nil
}
