package server

import (
	"database/sql"
	"encoding/binary"
	"math"
	"net/http"
	"time"
	"weatherstation/internal/database"

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

type radarTileRecord struct {
	DT     time.Time
	Z      int
	Y      int
	X      int
	Width  int
	Height int
	West   float64
	South  float64
	East   float64
	North  float64
	ResDeg float64
	Data   []byte
}

type radarTileResponse struct {
	DT     string       `json:"dt"`
	Z      int          `json:"z"`
	Y      int          `json:"y"`
	X      int          `json:"x"`
	Width  int          `json:"width"`
	Height int          `json:"height"`
	West   float64      `json:"west"`
	South  float64      `json:"south"`
	East   float64      `json:"east"`
	North  float64      `json:"north"`
	ResDeg float64      `json:"res_deg"`
	Values [][]*float64 `json:"values"` // null 表示无效值
}

func getLatestRadarTile(db *sql.DB, z, y, x int) (*radarTileRecord, error) {
	const q = `
        SELECT dt, z, y, x, width, height, west, south, east, north, res_deg, data
        FROM radar_tiles
        WHERE z=$1 AND y=$2 AND x=$3
        ORDER BY dt DESC
        LIMIT 1`
	var r radarTileRecord
	err := db.QueryRow(q, z, y, x).Scan(
		&r.DT, &r.Z, &r.Y, &r.X, &r.Width, &r.Height,
		&r.West, &r.South, &r.East, &r.North, &r.ResDeg, &r.Data,
	)
	if err != nil {
		return nil, err
	}
	return &r, nil
}

func getRadarTileAt(db *sql.DB, z, y, x int, dt time.Time) (*radarTileRecord, error) {
	const q = `
        SELECT dt, z, y, x, width, height, west, south, east, north, res_deg, data
        FROM radar_tiles
        WHERE z=$1 AND y=$2 AND x=$3 AND dt=$4
        LIMIT 1`
	var r radarTileRecord
	err := db.QueryRow(q, z, y, x, dt).Scan(
		&r.DT, &r.Z, &r.Y, &r.X, &r.Width, &r.Height,
		&r.West, &r.South, &r.East, &r.North, &r.ResDeg, &r.Data,
	)
	if err != nil {
		return nil, err
	}
	return &r, nil
}

// latestRadarTileHandler 返回指定 z/y/x 的最新瓦片，包含栅格 dBZ 值及元数据
func latestRadarTileHandler(c *gin.Context) {
	// 固定默认 7/40/102，可通过查询参数覆盖
	z := parseIntDefault(c.Query("z"), 7)
	y := parseIntDefault(c.Query("y"), 40)
	x := parseIntDefault(c.Query("x"), 102)

	rec, err := getLatestRadarTile(database.GetDB(), z, y, x)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "未找到雷达瓦片"})
		return
	}

	// 解码大端 int16 → dBZ (raw/10). >=32766 视为无效(null)
	w, h := rec.Width, rec.Height
	vals := make([][]*float64, h)
	// 每行 256 单元，每单元 2 字节
	if len(rec.Data) < w*h*2 {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "数据长度异常"})
		return
	}
	off := 0
	for row := 0; row < h; row++ {
		rowVals := make([]*float64, w)
		for col := 0; col < w; col++ {
			v := int16(binary.BigEndian.Uint16(rec.Data[off : off+2]))
			off += 2
			if v >= 32766 {
				rowVals[col] = nil
				continue
			}
			dbz := float64(v) / 10.0
			// 限幅到 [0,75]（大部分 CREF 标准范围），便于颜色映射
			if dbz < 0 {
				dbz = 0
			} else if dbz > 75 {
				dbz = 75
			}
			vv := dbz
			rowVals[col] = &vv
		}
		vals[row] = rowVals
	}

	resp := radarTileResponse{
		DT:     rec.DT.Format("2006-01-02 15:04:05"),
		Z:      rec.Z,
		Y:      rec.Y,
		X:      rec.X,
		Width:  rec.Width,
		Height: rec.Height,
		West:   rec.West,
		South:  rec.South,
		East:   rec.East,
		North:  rec.North,
		ResDeg: rec.ResDeg,
		Values: vals,
	}
	c.JSON(http.StatusOK, resp)
}

// radarTileAtHandler 返回指定 z/y/x 的指定时间瓦片
func radarTileAtHandler(c *gin.Context) {
	z := parseIntDefault(c.Query("z"), 7)
	y := parseIntDefault(c.Query("y"), 40)
	x := parseIntDefault(c.Query("x"), 102)
	dtStr := c.Query("dt")
	if dtStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "缺少 dt 参数（YYYY-MM-DD HH:MM:SS）"})
		return
	}
	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	dt, err := time.ParseInLocation("2006-01-02 15:04:05", dtStr, loc)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 dt 格式"})
		return
	}
	rec, err := getRadarTileAt(database.GetDB(), z, y, x, dt)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "未找到指定时间瓦片"})
		return
	}
	w, h := rec.Width, rec.Height
	if len(rec.Data) < w*h*2 {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "数据长度异常"})
		return
	}
	vals := make([][]*float64, h)
	off := 0
	for row := 0; row < h; row++ {
		rowVals := make([]*float64, w)
		for col := 0; col < w; col++ {
			v := int16(binary.BigEndian.Uint16(rec.Data[off : off+2]))
			off += 2
			if v >= 32766 {
				rowVals[col] = nil
				continue
			}
			dbz := float64(v) / 10.0
			if dbz < 0 {
				dbz = 0
			} else if dbz > 75 {
				dbz = 75
			}
			vv := dbz
			rowVals[col] = &vv
		}
		vals[row] = rowVals
	}
	resp := radarTileResponse{
		DT:     rec.DT.Format("2006-01-02 15:04:05"),
		Z:      rec.Z,
		Y:      rec.Y,
		X:      rec.X,
		Width:  rec.Width,
		Height: rec.Height,
		West:   rec.West,
		South:  rec.South,
		East:   rec.East,
		North:  rec.North,
		ResDeg: rec.ResDeg,
		Values: vals,
	}
	c.JSON(http.StatusOK, resp)
}

// radarTileTimesHandler 返回指定 z/y/x 的可用时间列表（倒序）
func radarTileTimesHandler(c *gin.Context) {
	z := parseIntDefault(c.Query("z"), 7)
	y := parseIntDefault(c.Query("y"), 40)
	x := parseIntDefault(c.Query("x"), 102)
	fromStr := c.Query("from")
	toStr := c.Query("to")
	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	var rows *sql.Rows
	var err error
	if fromStr != "" && toStr != "" {
		from, err1 := time.ParseInLocation("2006-01-02 15:04:05", fromStr, loc)
		to, err2 := time.ParseInLocation("2006-01-02 15:04:05", toStr, loc)
		if err1 != nil || err2 != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 from/to 时间格式"})
			return
		}
		const qRange = `
            SELECT dt FROM radar_tiles
            WHERE z=$1 AND y=$2 AND x=$3 AND dt BETWEEN $4 AND $5
            ORDER BY dt DESC`
		rows, err = database.GetDB().Query(qRange, z, y, x, from, to)
	} else {
		limit := parseIntDefault(c.Query("limit"), 48)
		const q = `
            SELECT dt FROM radar_tiles
            WHERE z=$1 AND y=$2 AND x=$3
            ORDER BY dt DESC
            LIMIT $4`
		rows, err = database.GetDB().Query(q, z, y, x, limit)
	}
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "查询时间列表失败"})
		return
	}
	defer rows.Close()
	var times []string
	for rows.Next() {
		var dt time.Time
		if err := rows.Scan(&dt); err != nil {
			continue
		}
		times = append(times, dt.Format("2006-01-02 15:04:05"))
	}
	c.JSON(http.StatusOK, gin.H{"times": times})
}

func parseIntDefault(s string, def int) int {
	if s == "" {
		return def
	}
	var n int
	_, err := fmtSscanf(s, &n)
	if err != nil || n == 0 || n == math.MinInt || n == math.MaxInt {
		return def
	}
	return n
}

// fmtSscanf is a tiny wrapper to avoid importing fmt only for Sscanf
func fmtSscanf(s string, n *int) (int, error) {
	// naive fast parse
	sign := 1
	i := 0
	if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
		if s[0] == '-' {
			sign = -1
		}
		i = 1
	}
	val := 0
	for ; i < len(s); i++ {
		ch := s[i]
		if ch < '0' || ch > '9' {
			return 0, fmtError("invalid")
		}
		val = val*10 + int(ch-'0')
	}
	*n = sign * val
	return 1, nil
}

type fmtError string

func (e fmtError) Error() string { return string(e) }

// ---------------- Radar station realtime API ----------------

type radarWeatherRecord struct {
	Alias         string
	Lat           float64
	Lon           float64
	DT            time.Time
	Temperature   float64
	Humidity      float64
	Cloudrate     float64
	Visibility    float64
	Dswrf         float64
	WindSpeed     float64
	WindDirection float64
	Pressure      float64
}

type radarWeatherResponse struct {
	Alias         string  `json:"alias"`
	Lat           float64 `json:"lat"`
	Lon           float64 `json:"lon"`
	DT            string  `json:"dt"`
	Temperature   float64 `json:"temperature"`
	Humidity      float64 `json:"humidity"`
	Cloudrate     float64 `json:"cloudrate"`
	Visibility    float64 `json:"visibility"`
	Dswrf         float64 `json:"dswrf"`
	WindSpeed     float64 `json:"wind_speed"`
	WindDirection float64 `json:"wind_direction"`
	Pressure      float64 `json:"pressure"`
}

func latestRadarWeatherHandler(c *gin.Context) {
	alias := c.Query("alias")
	if alias == "" {
		alias = "南宁雷达站"
	}
	const q = `
        SELECT alias, lat, lon, dt,
               temperature, humidity, cloudrate, visibility, dswrf,
               wind_speed, wind_direction, pressure
        FROM radar_weather
        WHERE alias = $1
        ORDER BY dt DESC
        LIMIT 1`
	var r radarWeatherRecord
	err := database.GetDB().QueryRow(q, alias).Scan(
		&r.Alias, &r.Lat, &r.Lon, &r.DT,
		&r.Temperature, &r.Humidity, &r.Cloudrate, &r.Visibility, &r.Dswrf,
		&r.WindSpeed, &r.WindDirection, &r.Pressure,
	)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "未找到实时气象数据"})
		return
	}
	resp := radarWeatherResponse{
		Alias:         r.Alias,
		Lat:           r.Lat,
		Lon:           r.Lon,
		DT:            r.DT.Format("2006-01-02 15:04:05"),
		Temperature:   r.Temperature,
		Humidity:      r.Humidity,
		Cloudrate:     r.Cloudrate,
		Visibility:    r.Visibility,
		Dswrf:         r.Dswrf,
		WindSpeed:     r.WindSpeed,
		WindDirection: r.WindDirection,
		Pressure:      r.Pressure,
	}
	c.JSON(http.StatusOK, resp)
}

// radarWeatherAtHandler returns the radar weather record at the given dt (CST),
// rounded/exact 10-minute bucket time string "YYYY-MM-DD HH:MM:SS".
func radarWeatherAtHandler(c *gin.Context) {
	alias := c.Query("alias")
	if alias == "" {
		alias = "南宁雷达站"
	}
	dtStr := c.Query("dt")
	if dtStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "缺少 dt 参数（YYYY-MM-DD HH:MM:SS）"})
		return
	}
	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	dt, err := time.ParseInLocation("2006-01-02 15:04:05", dtStr, loc)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的 dt 格式"})
		return
	}
	const q = `
        SELECT alias, lat, lon, dt,
               temperature, humidity, cloudrate, visibility, dswrf,
               wind_speed, wind_direction, pressure
        FROM radar_weather
        WHERE alias = $1 AND dt = $2
        LIMIT 1`
	var r radarWeatherRecord
	err = database.GetDB().QueryRow(q, alias, dt).Scan(
		&r.Alias, &r.Lat, &r.Lon, &r.DT,
		&r.Temperature, &r.Humidity, &r.Cloudrate, &r.Visibility, &r.Dswrf,
		&r.WindSpeed, &r.WindDirection, &r.Pressure,
	)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "未找到指定时间的实时气象数据"})
		return
	}
	resp := radarWeatherResponse{
		Alias:         r.Alias,
		Lat:           r.Lat,
		Lon:           r.Lon,
		DT:            r.DT.Format("2006-01-02 15:04:05"),
		Temperature:   r.Temperature,
		Humidity:      r.Humidity,
		Cloudrate:     r.Cloudrate,
		Visibility:    r.Visibility,
		Dswrf:         r.Dswrf,
		WindSpeed:     r.WindSpeed,
		WindDirection: r.WindDirection,
		Pressure:      r.Pressure,
	}
	c.JSON(http.StatusOK, resp)
}
