package httpapi

import (
	"context"
	"time"

	"github.com/dtoro/oikos/internal/httpapi/gen"
)

// GetDashboardSummary returns one round-trip overview for the control room
// home page: entity counts, health rollup, open signals, pending approvals,
// executions in the last 24h, and an event-rate sparkline.
func (s *Server) GetDashboardSummary(ctx context.Context, req gen.GetDashboardSummaryRequestObject) (gen.GetDashboardSummaryResponseObject, error) {
	resp := gen.DashboardSummary{
		EntitiesByType:    map[string]int{},
		EntitiesByState:   map[string]int{},
		SignalsBySeverity: map[string]int{},
		ExecutionsByState: map[string]int{},
	}

	rows, err := s.pool.Query(ctx, `SELECT type, count(*) FROM entities GROUP BY type`)
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		var typ string
		var n int
		if err := rows.Scan(&typ, &n); err != nil {
			rows.Close()
			return nil, err
		}
		resp.EntitiesByType[typ] = n
	}
	rows.Close()
	if err := rows.Err(); err != nil {
		return nil, err
	}

	rows, err = s.pool.Query(ctx, `SELECT coalesce(state, 'unknown'), count(*) FROM entities GROUP BY state`)
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		var state string
		var n int
		if err := rows.Scan(&state, &n); err != nil {
			rows.Close()
			return nil, err
		}
		resp.EntitiesByState[state] = n
	}
	rows.Close()
	if err := rows.Err(); err != nil {
		return nil, err
	}

	// Exclude 'check' entities (internal probes) — only entities actually
	// being monitored should count toward the fleet health rollup.
	rows, err = s.pool.Query(ctx, `
		SELECT st.health, count(*)
		FROM entity_status st JOIN entities e ON e.id = st.entity_id
		WHERE e.type <> 'check'
		GROUP BY st.health`)
	if err != nil {
		return nil, err
	}
	stale := 0
	for rows.Next() {
		var health string
		var n int
		if err := rows.Scan(&health, &n); err != nil {
			rows.Close()
			return nil, err
		}
		switch health {
		case "healthy":
			resp.Health.Healthy = n
		case "degraded":
			resp.Health.Degraded = n
		case "down":
			resp.Health.Down = n
		case "stale":
			stale = n
		default:
			resp.Health.Unknown = n
		}
	}
	rows.Close()
	if err := rows.Err(); err != nil {
		return nil, err
	}
	if stale > 0 {
		resp.Health.Stale = &stale
	}

	rows, err = s.pool.Query(ctx, `
		SELECT severity, count(*) FROM signals
		WHERE state NOT IN ('resolved', 'failed')
		GROUP BY severity`)
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		var severity string
		var n int
		if err := rows.Scan(&severity, &n); err != nil {
			rows.Close()
			return nil, err
		}
		resp.SignalsBySeverity[severity] = n
	}
	rows.Close()
	if err := rows.Err(); err != nil {
		return nil, err
	}

	if err := s.pool.QueryRow(ctx,
		`SELECT count(*) FROM approvals WHERE status = 'pending'`,
	).Scan(&resp.ApprovalsPending); err != nil {
		return nil, err
	}

	rows, err = s.pool.Query(ctx, `
		SELECT status, count(*) FROM executions
		WHERE created_at > now() - interval '24 hours'
		GROUP BY status`)
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		var status string
		var n int
		if err := rows.Scan(&status, &n); err != nil {
			rows.Close()
			return nil, err
		}
		resp.ExecutionsByState[status] = n
	}
	rows.Close()
	if err := rows.Err(); err != nil {
		return nil, err
	}

	rows, err = s.pool.Query(ctx, `
		SELECT date_trunc('hour', ts) + (extract(minute FROM ts)::int / 5) * interval '5 minutes' AS bucket,
		       count(*)
		FROM events
		WHERE ts > now() - interval '6 hours'
		GROUP BY bucket
		ORDER BY bucket`)
	if err != nil {
		return nil, err
	}
	for rows.Next() {
		var bucket time.Time
		var n int
		if err := rows.Scan(&bucket, &n); err != nil {
			rows.Close()
			return nil, err
		}
		resp.EventRate = append(resp.EventRate, struct {
			Bucket time.Time `json:"bucket"`
			Count  int       `json:"count"`
		}{Bucket: bucket, Count: n})
	}
	rows.Close()
	if err := rows.Err(); err != nil {
		return nil, err
	}

	return gen.GetDashboardSummary200JSONResponse(resp), nil
}
