package store

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

// LoadPresenceState — returns the singleton hysteresis row, or a cold-start
// default (away, score 0) when no row exists yet. fail-closed.
func (s *Store) LoadPresenceState(ctx context.Context) (bucket Bucket, score float64, updated time.Time, err error) {
	var b string
	var updMilli int64
	row := s.db.QueryRowContext(ctx,
		`SELECT last_bucket, last_score, updated_ts FROM presence_state WHERE id = 1`)
	err = row.Scan(&b, &score, &updMilli)
	if errors.Is(err, sql.ErrNoRows) {
		return Away, 0.0, time.Time{}, nil
	}
	if err != nil {
		return "", 0, time.Time{}, fmt.Errorf("load presence_state: %w", err)
	}
	return Bucket(b), score, time.UnixMilli(updMilli).UTC(), nil
}

// SavePresenceState — upsert the singleton row. called every tick after resolve hysteresis.
func (s *Store) SavePresenceState(ctx context.Context, bucket Bucket, score float64, now time.Time) error {
	_, err := s.db.ExecContext(ctx, `
		INSERT INTO presence_state (id, last_bucket, last_score, updated_ts) VALUES (1, ?, ?, ?)
		ON CONFLICT(id) DO UPDATE SET last_bucket = excluded.last_bucket,
		                              last_score   = excluded.last_score,
		                              updated_ts   = excluded.updated_ts`,
		string(bucket), score, now.UnixMilli())
	if err != nil {
		return fmt.Errorf("save presence_state: %w", err)
	}
	return nil
}

// PresenceProbes — gather the latest non-voided fact ts per signal key.
// Returns a SignalProbe slice aligned with PresenceSignals. nil LastTs where
// the key has no data. This is the only I/O presence needs; the actual score
// computation happens in the pure PresenceScore() function.
func (s *Store) PresenceProbes(ctx context.Context) ([]SignalProbe, error) {
	probes := make([]SignalProbe, 0, len(PresenceSignals))
	for _, sig := range PresenceSignals {
		f, err := s.LatestFact(ctx, sig.Key)
		if errors.Is(err, ErrNoFact) {
			probes = append(probes, SignalProbe{Key: sig.Key, LastTs: nil})
			continue
		}
		if err != nil {
			return nil, err
		}
		t := f.Ts
		probes = append(probes, SignalProbe{Key: sig.Key, LastTs: &t})
	}
	return probes, nil
}
