package selftest

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"weatherstation/internal/database"
)

// Run 执行启动前自检
// 1) 数据库可用 2) 关键表存在 3) 基础查询可执行
func Run(ctx context.Context) error {
	db := database.GetDB()
	if err := pingDB(ctx, db); err != nil {
		return fmt.Errorf("数据库连通性失败: %w", err)
	}
	if err := ensureTables(ctx, db); err != nil {
		return fmt.Errorf("关键表缺失: %w", err)
	}
	if err := basicQuery(ctx, db); err != nil {
		return fmt.Errorf("基础查询失败: %w", err)
	}
	return nil
}

func pingDB(ctx context.Context, db *sql.DB) error {
	ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
	defer cancel()
	return db.PingContext(ctx)
}

func ensureTables(ctx context.Context, db *sql.DB) error {
	required := []string{
		"public.stations",
		"public.rs485_weather_data",
		"public.rs485_weather_10min",
		"public.forecast_hourly",
	}
	for _, t := range required {
		var exists bool
		if err := db.QueryRowContext(ctx, "SELECT to_regclass($1) IS NOT NULL", t).Scan(&exists); err != nil {
			return err
		}
		if !exists {
			return fmt.Errorf("缺少表: %s", t)
		}
	}
	return nil
}

func basicQuery(ctx context.Context, db *sql.DB) error {
	// 若无站点则跳过后续测试
	var stationID string
	_ = db.QueryRowContext(ctx, "SELECT station_id FROM stations LIMIT 1").Scan(&stationID)

	// 10分钟表可被查询（允许为空）
	var cnt int
	if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM rs485_weather_10min").Scan(&cnt); err != nil {
		return err
	}

	// 若有站点，做一次安全时间窗聚合验证（不要求有数据，只要语句可执行）
	if stationID != "" {
		from := time.Now().Add(-2 * time.Hour).Truncate(time.Hour)
		to := time.Now().Truncate(time.Hour)
		_, err := db.QueryContext(ctx,
			`WITH base AS (
				SELECT * FROM rs485_weather_10min WHERE station_id=$1 AND bucket_start >= $2 AND bucket_start <= $3
			), g AS (
				SELECT date_trunc('hour', bucket_start) AS grp, SUM(sample_count) AS n_sum FROM base GROUP BY 1
			) SELECT COUNT(*) FROM g`, stationID, from, to,
		)
		if err != nil {
			return err
		}
	}
	return nil
}
