package handler

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// ProcessSensorReadingMessage parses a sensor reading MQTT message and stores it.
// Returns handled=false when the payload does not look like a sensor reading.
func (h *Handler) ProcessSensorReadingMessage(payload []byte) (bool, error) {
	if h == nil || h.DB == nil {
		return false, nil
	}

	var msg struct {
		Type     string          `json:"type"`
		SensorID string          `json:"sensor_id"`
		Value    json.RawMessage `json:"value"`
		ValueAt  string          `json:"value_at"`
	}
	if err := json.Unmarshal(payload, &msg); err != nil {
		return false, nil
	}

	msgType := strings.ToLower(strings.TrimSpace(msg.Type))
	if msgType != "" && msgType != "sensor_reading" && msgType != "sensor_value" {
		return false, nil
	}
	if strings.TrimSpace(msg.SensorID) == "" || len(msg.Value) == 0 {
		return false, nil
	}

	value, err := parseSensorValue(msg.Value)
	if err != nil {
		return true, fmt.Errorf("invalid sensor value: %w", err)
	}

	valueAt := time.Now().UTC()
	if strings.TrimSpace(msg.ValueAt) != "" {
		parsed, err := time.Parse(time.RFC3339, msg.ValueAt)
		if err != nil {
			return true, fmt.Errorf("invalid value_at: %w", err)
		}
		valueAt = parsed
	}

	var exists int
	if err := h.DB.QueryRow("SELECT COUNT(1) FROM sensors WHERE id = UUID_TO_BIN(?)", msg.SensorID).Scan(&exists); err != nil {
		return true, fmt.Errorf("failed to check sensor: %w", err)
	}
	if exists == 0 {
		return true, fmt.Errorf("sensor not found: %s", msg.SensorID)
	}

	if _, err := h.DB.Exec(
		"INSERT INTO sensor_readings (sensor_id, value, value_at) VALUES (UUID_TO_BIN(?), ?, ?)",
		msg.SensorID,
		value,
		valueAt,
	); err != nil {
		return true, fmt.Errorf("failed to insert sensor reading: %w", err)
	}

	return true, nil
}

func parseSensorValue(raw json.RawMessage) (float64, error) {
	var v any
	if err := json.Unmarshal(raw, &v); err != nil {
		return 0, err
	}
	switch t := v.(type) {
	case float64:
		return t, nil
	case bool:
		if t {
			return 1, nil
		}
		return 0, nil
	case string:
		if strings.EqualFold(t, "true") {
			return 1, nil
		}
		if strings.EqualFold(t, "false") {
			return 0, nil
		}
		f, err := strconv.ParseFloat(t, 64)
		if err != nil {
			return 0, err
		}
		return f, nil
	default:
		return 0, fmt.Errorf("unsupported value type")
	}
}
