package fundmarket

import (
	"math/big"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	db "github.com/gothinkster/golang-gin-realworld-example-app/common"
)

// GetNetDeposited computes the net USDC deposited by a wallet address across all YT vaults.
//
// GET /api/fundmarket/net-deposited?address=0x...&chain_id=97
//
// Net deposited = Σ(amountIn WHERE tokenIn=USDC) - Σ(amountOut WHERE tokenOut=USDC)
// (buy YT: USDC → YT, tokenIn=USDC; sell YT: YT → USDC, tokenOut=USDC)
//
// Returns netDepositedUSD (float64) for the frontend to compute:
//   Your Total Earning = currentValue (on-chain) - netDepositedUSD
func GetNetDeposited(c *gin.Context) {
	address := strings.ToLower(c.Query("address"))
	if address == "" {
		c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "address required"})
		return
	}

	chainIDStr := c.DefaultQuery("chain_id", "97")
	database := db.GetDB()

	// Look up USDC address for this chain (token_role = 'stablecoin')
	var usdcAddr struct {
		ContractAddress string `gorm:"column:contract_address"`
	}
	if err := database.Table("assets").
		Where("token_role = 'stablecoin' AND chain_id = ?", chainIDStr).
		Select("contract_address").
		First(&usdcAddr).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "USDC address not found"})
		return
	}
	usdcAddress := strings.ToLower(usdcAddr.ContractAddress)

	// Sum amountIn where tokenIn = USDC (user bought YT, paid USDC)
	type sumResult struct {
		Total string
	}
	var buySum sumResult
	database.Raw(`
		SELECT COALESCE(SUM(CAST(amount_in AS DECIMAL(65,0))), 0) AS total
		FROM yt_swap_records
		WHERE account = ? AND chain_id = ? AND LOWER(token_in) = ?
	`, address, chainIDStr, usdcAddress).Scan(&buySum)

	// Sum amountOut where tokenOut = USDC (user sold YT, received USDC)
	var sellSum sumResult
	database.Raw(`
		SELECT COALESCE(SUM(CAST(amount_out AS DECIMAL(65,0))), 0) AS total
		FROM yt_swap_records
		WHERE account = ? AND chain_id = ? AND LOWER(token_out) = ?
	`, address, chainIDStr, usdcAddress).Scan(&sellSum)

	buyWei, _ := new(big.Int).SetString(buySum.Total, 10)
	sellWei, _ := new(big.Int).SetString(sellSum.Total, 10)
	if buyWei == nil {
		buyWei = big.NewInt(0)
	}
	if sellWei == nil {
		sellWei = big.NewInt(0)
	}

	netWei := new(big.Int).Sub(buyWei, sellWei)
	if netWei.Sign() < 0 {
		netWei = big.NewInt(0)
	}

	// Convert from 18-decimal wei to float64 USD
	divisor := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))
	netUSD, _ := new(big.Float).Quo(new(big.Float).SetInt(netWei), divisor).Float64()

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"address":         address,
			"chainId":         chainIDStr,
			"usdcAddress":     usdcAddress,
			"buyWei":          buyWei.String(),
			"sellWei":         sellWei.String(),
			"netDepositedWei": netWei.String(),
			"netDepositedUSD": netUSD,
		},
	})
}
