package alp

import (
	"net/http"
	"time"

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

// GetALPHistory returns historical APR and price data from alp_snapshots.
// Each point is computed from consecutive snapshot pairs.
// Query param: days=30 (default 30, max 90)
func GetALPHistory(c *gin.Context) {
	database := db.GetDB()

	days := 30
	if d := c.Query("days"); d != "" {
		if v := parseInt(d, 30); v > 0 && v <= 90 {
			days = v
		}
	}

	since := time.Now().UTC().Add(-time.Duration(days) * 24 * time.Hour)

	var snaps []models.ALPSnapshot
	if err := database.
		Where("snapshot_time >= ?", since).
		Order("snapshot_time ASC").
		Find(&snaps).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()})
		return
	}

	type Point struct {
		Time        string  `json:"time"`
		TS          int64   `json:"ts"`
		PoolAPR     float64 `json:"poolAPR"`
		ALPPrice    float64 `json:"alpPrice"`
		FeeSurplus  float64 `json:"feeSurplus"`
		PoolValue   float64 `json:"poolValue"`
	}

	// Deduplicate: keep the latest snapshot per calendar day (UTC)
	dayMap := make(map[string]models.ALPSnapshot)
	dayOrder := make([]string, 0)
	for _, snap := range snaps {
		key := snap.SnapshotTime.UTC().Format("2006-01-02")
		if _, exists := dayMap[key]; !exists {
			dayOrder = append(dayOrder, key)
		}
		dayMap[key] = snap // overwrite keeps the latest of the day
	}
	daily := make([]models.ALPSnapshot, 0, len(dayOrder))
	for _, key := range dayOrder {
		daily = append(daily, dayMap[key])
	}

	points := make([]Point, 0, len(daily))
	for i, snap := range daily {
		apr := 0.0
		if i > 0 {
			prev := daily[i-1]
			d := snap.SnapshotTime.Sub(prev.SnapshotTime).Hours() / 24
			if d > 0 && snap.PoolValue > 0 && snap.FeeSurplus > prev.FeeSurplus {
				apr = (snap.FeeSurplus-prev.FeeSurplus) / snap.PoolValue / d * 365 * 100
			}
		}
		points = append(points, Point{
			Time:       snap.SnapshotTime.Format("01/02"),
			TS:         snap.SnapshotTime.Unix(),
			PoolAPR:    apr,
			ALPPrice:   snap.ALPPrice,
			FeeSurplus: snap.FeeSurplus,
			PoolValue:  snap.PoolValue,
		})
	}

	c.JSON(http.StatusOK, gin.H{"success": true, "data": points})
}

func parseInt(s string, def int) int {
	if s == "" {
		return def
	}
	v := 0
	for _, c := range s {
		if c < '0' || c > '9' {
			return def
		}
		v = v*10 + int(c-'0')
	}
	return v
}

// GetALPStats returns current ALP pool APR calculated from snapshots.
// TVL and ALP price are read directly from chain on the frontend;
// this endpoint only provides the APR which requires historical data.
func GetALPStats(c *gin.Context) {
	database := db.GetDB()

	// Latest snapshot
	var latest models.ALPSnapshot
	if err := database.Order("snapshot_time DESC").First(&latest).Error; err != nil {
		c.JSON(http.StatusOK, gin.H{
			"success": true,
			"data":    gin.H{"poolAPR": 0.0, "rewardAPR": 0.0},
		})
		return
	}

	// Use the oldest available snapshot as reference (maximises data coverage)
	var past models.ALPSnapshot
	database.Order("snapshot_time ASC").First(&past)
	found := past.ID != 0 && past.ID != latest.ID

	poolAPR := 0.0
	if found && latest.PoolValue > 0 && past.FeeSurplus < latest.FeeSurplus {
		days := latest.SnapshotTime.Sub(past.SnapshotTime).Hours() / 24
		if days > 0 {
			surplusDelta := latest.FeeSurplus - past.FeeSurplus
			poolAPR = surplusDelta / latest.PoolValue / days * 365 * 100 // annualized %
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"poolAPR":   poolAPR,
			"rewardAPR": 0.0, // placeholder until reward contract is connected
		},
	})
}
