package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// Untimed diagnostic: samples backend waits while a write-bearing endpoint runs.
// It is not a benchmark and its polling overhead must not enter performance claims.
func diagnoseWaits(ctx context.Context, dsn, url, output string, n, concurrency int) error {
	c, err := openDB(ctx, dsn)
	if err != nil {
		return err
	}
	defer c.Close(ctx)
	if err = fixture(ctx, c); err != nil {
		return err
	}
	done := make(chan []float64, 1)
	client := &http.Client{Timeout: 10 * time.Second}
	go func() {
		durations := make([]float64, n)
		jobs := make(chan int)
		var wg sync.WaitGroup
		for range concurrency {
			wg.Add(1)
			go func() {
				defer wg.Done()
				for i := range jobs {
					start := time.Now()
					resp, err := client.Get(url + "/api/posts/1")
					if err == nil {
						io.Copy(io.Discard, resp.Body)
						resp.Body.Close()
					}
					durations[i] = float64(time.Since(start)) / 1e6
				}
			}()
		}
		for i := 0; i < n; i++ {
			jobs <- i
		}
		close(jobs)
		wg.Wait()
		done <- durations
	}()
	counts := map[string]int{}
	ticker := time.NewTicker(5 * time.Millisecond)
	defer ticker.Stop()
	for {
		select {
		case durations := <-done:
			if err = os.MkdirAll(filepath.Dir(output), 0755); err != nil {
				return err
			}
			raw, _ := json.MarshalIndent(map[string]any{"diagnostic_only": true, "wait_samples": counts, "latencies_ms": durations}, "", "  ")
			if err = os.WriteFile(output, append(raw, '\n'), 0644); err != nil {
				return err
			}
			fmt.Println(counts)
			return nil
		case <-ticker.C:
			rows, err := c.Query(ctx, `SELECT coalesce(wait_event_type,'CPU'),coalesce(wait_event,'running') FROM pg_stat_activity WHERE datname=current_database() AND pid<>pg_backend_pid() AND state='active'`)
			if err != nil {
				return err
			}
			for rows.Next() {
				var kind, event string
				rows.Scan(&kind, &event)
				counts[kind+":"+event]++
			}
			err = rows.Err()
			rows.Close()
			if err != nil {
				return err
			}
		}
	}
}
