package server

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"
	"weatherstation/core/internal/data"
)

import "github.com/gin-gonic/gin"

func handleHealth(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"status": "ok", "ts": time.Now().UTC().Format(time.RFC3339)})
}

func handleSystemStatus(c *gin.Context) {
	online := data.OnlineDevices()
	c.JSON(http.StatusOK, gin.H{
		"online_devices": online,
		"server_time":    time.Now().Format("2006-01-02 15:04:05"),
	})
}

func handleStations(c *gin.Context) {
	stations, err := data.Stations()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("query stations failed: %v", err)})
		return
	}
	for i := range stations {
		if len(stations[i].StationID) > 6 {
			hexID := stations[i].StationID[len(stations[i].StationID)-6:]
			if decimalID, err := strconv.ParseInt(hexID, 16, 64); err == nil {
				stations[i].DecimalID = strconv.FormatInt(decimalID, 10)
			}
		}
	}
	c.JSON(http.StatusOK, stations)
}

func handleData(c *gin.Context) {
	idParam := c.Query("hex_id")
	startTime := c.Query("start_time")
	endTime := c.Query("end_time")
	interval := c.DefaultQuery("interval", "1hour")

	if idParam == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "missing hex_id"})
		return
	}
	upper := strings.ToUpper(idParam)
	var b strings.Builder
	for i := 0; i < len(upper); i++ {
		ch := upper[i]
		if (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') {
			b.WriteByte(ch)
		}
	}
	hex := b.String()
	if hex == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid hex_id"})
		return
	}
	if len(hex) < 6 {
		hex = strings.Repeat("0", 6-len(hex)) + hex
	} else if len(hex) > 6 {
		hex = hex[len(hex)-6:]
	}
	stationID := fmt.Sprintf("RS485-%s", hex)

	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	start, err := time.ParseInLocation("2006-01-02 15:04:05", startTime, loc)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid start_time"})
		return
	}
	end, err := time.ParseInLocation("2006-01-02 15:04:05", endTime, loc)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid end_time"})
		return
	}

	var points interface{}
	if interval == "raw" {
		points, err = data.SeriesRaw(stationID, start, end)
	} else {
		points, err = data.SeriesFrom10Min(stationID, start, end, interval)
	}
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("query failed: %v", err)})
		return
	}
	c.JSON(http.StatusOK, points)
}

func handleForecast(c *gin.Context) {
	stationID := c.Query("station_id")
	from := c.Query("from")
	to := c.Query("to")
	provider := c.Query("provider")
	versionsStr := c.DefaultQuery("versions", "1")
	versions, _ := strconv.Atoi(versionsStr)
	if versions <= 0 {
		versions = 1
	}

	if stationID == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "missing station_id"})
		return
	}

	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}

	var start, end time.Time
	var err error
	if from == "" || to == "" {
		now := time.Now().In(loc)
		start = now.Truncate(time.Hour).Add(1 * time.Hour)
		end = start.Add(3 * time.Hour)
	} else {
		start, err = time.ParseInLocation("2006-01-02 15:04:05", from, loc)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid from"})
			return
		}
		end, err = time.ParseInLocation("2006-01-02 15:04:05", to, loc)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid to"})
			return
		}
	}

	points, err := data.Forecast(stationID, start, end, provider, versions)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("query forecast failed: %v", err)})
		return
	}
	c.JSON(http.StatusOK, points)
}
