package data

import (
	"context"
	"database/sql"
	"math"
	"time"
)

type WindowAgg struct {
	Ta sql.NullFloat64
	Ua sql.NullFloat64
	Pa sql.NullFloat64
	Sm sql.NullFloat64
	Dm sql.NullFloat64
}

// WindowAverages computes averages on rs485_weather_data over [start,end) window.
// Filters values < 0.001 as invalid. Wind direction averaged vectorially.
func WindowAverages(ctx context.Context, stationID string, start, end time.Time) (WindowAgg, error) {
	const q = `
        SELECT
          AVG(temperature) AS ta,
          AVG(humidity)    AS ua,
          AVG(pressure)    AS pa,
          AVG(CASE WHEN wind_speed >= 0.001 THEN wind_speed END) AS sm,
          DEGREES(
            ATAN2(
              AVG(CASE WHEN wind_speed >= 0.001 THEN SIN(RADIANS(wind_direction)) END),
              AVG(CASE WHEN wind_speed >= 0.001 THEN COS(RADIANS(wind_direction)) END)
            )
          ) AS dm
        FROM rs485_weather_data
        WHERE station_id = $1 AND timestamp >= $2 AND timestamp < $3`
	var agg WindowAgg
	err := DB().QueryRowContext(ctx, q, stationID, start, end).Scan(
		&agg.Ta, &agg.Ua, &agg.Pa, &agg.Sm, &agg.Dm,
	)
	if err != nil {
		return WindowAgg{}, err
	}
	// Normalize Dm to [0,360)
	if agg.Dm.Valid {
		v := agg.Dm.Float64
		if v < 0 {
			v += 360.0
		}
		// handle NaN from no data
		if math.IsNaN(v) {
			agg.Dm.Valid = false
		} else {
			agg.Dm.Float64 = v
		}
	}
	return agg, nil
}

// DailyRainSinceMidnight computes current_day_rain = max(0, latest - baselineAtMidnight).
// If baseline is null, returns 0.
func DailyRainSinceMidnight(ctx context.Context, stationID string, now time.Time) (float64, error) {
	// Midnight in Asia/Shanghai
	loc, _ := time.LoadLocation("Asia/Shanghai")
	if loc == nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	dayStart := time.Date(now.In(loc).Year(), now.In(loc).Month(), now.In(loc).Day(), 0, 0, 0, 0, loc)

	var baseline sql.NullFloat64
	const qBase = `SELECT rainfall FROM rs485_weather_data WHERE station_id=$1 AND timestamp <= $2 ORDER BY timestamp DESC LIMIT 1`
	_ = DB().QueryRowContext(ctx, qBase, stationID, dayStart).Scan(&baseline)

	var current sql.NullFloat64
	const qCur = `SELECT rainfall FROM rs485_weather_data WHERE station_id=$1 ORDER BY timestamp DESC LIMIT 1`
	_ = DB().QueryRowContext(ctx, qCur, stationID).Scan(&current)

	if !current.Valid || !baseline.Valid {
		return 0, nil
	}
	v := current.Float64 - baseline.Float64
	if v < 0 {
		v = 0
	}
	return v, nil
}
