package model

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

	"weatherstation/config"

	_ "github.com/lib/pq"
)

var db *sql.DB

func InitDB() error {
	cfg := config.GetConfig()

	connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
		cfg.Database.Host, cfg.Database.Port, cfg.Database.User,
		cfg.Database.Password, cfg.Database.DBName, cfg.Database.SSLMode)

	var err error
	db, err = sql.Open("postgres", connStr)
	if err != nil {
		return fmt.Errorf("无法连接到数据库: %v", err)
	}

	err = db.Ping()
	if err != nil {
		return fmt.Errorf("数据库连接测试失败: %v", err)
	}

	// 创建RS485数据表
	err = createRS485Table()
	if err != nil {
		return fmt.Errorf("创建RS485数据表失败: %v", err)
	}

	return nil
}

func createRS485Table() error {
	_, err := db.Exec(`
		CREATE TABLE IF NOT EXISTS rs485_weather_data (
			id BIGSERIAL PRIMARY KEY,
			station_id VARCHAR(50) NOT NULL,
			timestamp TIMESTAMPTZ NOT NULL,
			temperature DOUBLE PRECISION,
			humidity DOUBLE PRECISION,
			wind_speed DOUBLE PRECISION,
			wind_direction DOUBLE PRECISION,
			rainfall DOUBLE PRECISION,
			light DOUBLE PRECISION,
			uv DOUBLE PRECISION,
			pressure DOUBLE PRECISION,
			raw_data TEXT,
			FOREIGN KEY (station_id) REFERENCES stations(station_id),
			UNIQUE (station_id, timestamp)
		)`)
	if err != nil {
		return err
	}

	// 支持性索引（若已存在则不重复创建）
	if _, err = db.Exec(`CREATE INDEX IF NOT EXISTS idx_rwd_time ON rs485_weather_data (timestamp)`); err != nil {
		return err
	}
	if _, err = db.Exec(`CREATE INDEX IF NOT EXISTS idx_rwd_station_time ON rs485_weather_data (station_id, timestamp)`); err != nil {
		return err
	}
	return nil
}

func CloseDB() {
	if db != nil {
		db.Close()
	}
}

func ensureStationExists(stationID, password string) error {
	if db == nil {
		return fmt.Errorf("数据库未初始化")
	}

	var count int
	err := db.QueryRow("SELECT COUNT(*) FROM stations WHERE station_id = $1", stationID).Scan(&count)
	if err != nil {
		return fmt.Errorf("查询站点失败: %v", err)
	}

	if count == 0 {
		_, err = db.Exec("INSERT INTO stations (station_id, password) VALUES ($1, $2)", stationID, password)
		if err != nil {
			return fmt.Errorf("添加站点失败: %v", err)
		}
	} else {
		_, err = db.Exec("UPDATE stations SET password = $1, last_update = $2 WHERE station_id = $3",
			password, time.Now(), stationID)
		if err != nil {
			return fmt.Errorf("更新站点失败: %v", err)
		}
	}

	return nil
}

func SaveWeatherData(data interface{}, rawData string) error {
	if db == nil {
		return fmt.Errorf("数据库未初始化")
	}

	switch v := data.(type) {
	case *WeatherData:
		return saveWIFIWeatherData(v, rawData)
	case *RS485WeatherData:
		return saveRS485WeatherData(v)
	default:
		return fmt.Errorf("未知的数据类型")
	}
}

func saveWIFIWeatherData(data *WeatherData, rawData string) error {
	err := ensureStationExists(data.StationID, data.Password)
	if err != nil {
		return err
	}

	_, err = db.Exec(`
		INSERT INTO weather_data (
			station_id, timestamp, temp_f, humidity, dewpoint_f, windchill_f,
			wind_dir, wind_speed_mph, wind_gust_mph, rain_in, daily_rain_in,
			weekly_rain_in, monthly_rain_in, yearly_rain_in, total_rain_in,
			solar_radiation, uv, indoor_temp_f, indoor_humidity,
			abs_barometer_in, barometer_in, low_battery, raw_data
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)`,
		data.StationID, time.Now(),
		int(data.TempF*10), data.Humidity, int(data.DewpointF*10), int(data.WindchillF*10),
		data.WindDir, int(data.WindSpeedMph*100), int(data.WindGustMph*100),
		int(data.RainIn*1000), int(data.DailyRainIn*1000), int(data.WeeklyRainIn*1000),
		int(data.MonthlyRainIn*1000), int(data.YearlyRainIn*1000), int(data.TotalRainIn*1000),
		int(data.SolarRadiation*100), data.UV, int(data.IndoorTempF*10), data.IndoorHumidity,
		int(data.AbsBarometerIn*1000), int(data.BarometerIn*1000), data.LowBattery, rawData)

	if err != nil {
		return fmt.Errorf("保存WIFI气象数据失败: %v", err)
	}
	return nil
}

func saveRS485WeatherData(data *RS485WeatherData) error {
	stationID := fmt.Sprintf("RS485-%s", data.DeviceID)
	err := ensureStationExists(stationID, "")
	if err != nil {
		return err
	}

	_, err = db.Exec(`
		INSERT INTO rs485_weather_data (
			station_id, timestamp, temperature, humidity, wind_speed,
			wind_direction, rainfall, light, uv, pressure, raw_data
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
		stationID, data.ReceivedAt,
		data.Temperature, data.Humidity, data.WindSpeed,
		data.WindDirection, data.Rainfall, data.Light,
		data.UV, data.Pressure, data.RawDataHex)

	if err != nil {
		return fmt.Errorf("保存RS485气象数据失败: %v", err)
	}
	return nil
}
