package webrtc

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/labstack/echo/v4"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/testutil"

	"github.com/datarhei/core/v16/config"
)

func newTestHandler(t *testing.T) (*Handler, *prometheus.Registry) {
	t.Helper()
	s, err := New(config.DataWebRTC{Enable: true}, nil)
	if err != nil {
		t.Fatalf("New: %v", err)
	}
	h := NewHandler(s, 0)
	reg := prometheus.NewRegistry()
	h.InitMetrics(reg, "test")
	return h, reg
}

// TestMetrics_Subscribe404BumpsCounter checks that a 404 on unknown stream
// increments the request counter with the correct labels.
func TestMetrics_Subscribe404BumpsCounter(t *testing.T) {
	h, reg := newTestHandler(t)

	e := echo.New()
	req := httptest.NewRequest(http.MethodPost, "/whep/ghost", strings.NewReader("v=0\r\n"))
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)
	c.SetParamNames("id")
	c.SetParamValues("ghost")
	_ = h.Subscribe(c)

	if rec.Code != http.StatusNotFound {
		t.Fatalf("expected 404, got %d", rec.Code)
	}

	if err := testutil.GatherAndCompare(reg, strings.NewReader(`
# HELP dragonfork_webrtc_whep_requests_total Count of WHEP HTTP requests by route, HTTP status code, and stream.
# TYPE dragonfork_webrtc_whep_requests_total counter
dragonfork_webrtc_whep_requests_total{code="404",core="test",route="subscribe",stream_id="ghost"} 1
`), "dragonfork_webrtc_whep_requests_total"); err != nil {
		t.Fatal(err)
	}
}

// TestMetrics_GlobalCapBumpsCapRejection checks that a global cap 503 fires
// the cap_rejections counter with scope=global.
func TestMetrics_GlobalCapBumpsCapRejection(t *testing.T) {
	s, err := New(config.DataWebRTC{Enable: true}, nil)
	if err != nil {
		t.Fatalf("New: %v", err)
	}
	// maxPeers=1, but inject a stream so we get past lookup
	s.mu.Lock()
	s.streams["mystream"] = &processStream{id: "mystream"}
	s.mu.Unlock()

	h := NewHandlerWithCaps(s, 1, 0)
	reg := prometheus.NewRegistry()
	h.InitMetrics(reg, "test")
	// Force count to be at cap
	h.count = 1

	e := echo.New()
	req := httptest.NewRequest(http.MethodPost, "/whep/mystream", strings.NewReader("v=0\r\n"))
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)
	c.SetParamNames("id")
	c.SetParamValues("mystream")
	_ = h.Subscribe(c)

	if rec.Code != http.StatusServiceUnavailable {
		t.Fatalf("expected 503, got %d", rec.Code)
	}

	n := testutil.ToFloat64(h.met.capRejections.WithLabelValues("", "global"))
	if n != 1 {
		t.Fatalf("cap_rejections{scope=global}: want 1, got %v", n)
	}
}

// TestMetrics_CodecMismatchBumpsCounter checks that a 406 SDP with no H264
// increments codec_mismatches{kind=h264}.
func TestMetrics_CodecMismatchBumpsCounter(t *testing.T) {
	s, err := New(config.DataWebRTC{Enable: true}, nil)
	if err != nil {
		t.Fatalf("New: %v", err)
	}
	s.mu.Lock()
	s.streams["cam"] = &processStream{id: "cam"}
	s.mu.Unlock()

	h := NewHandler(s, 0)
	reg := prometheus.NewRegistry()
	h.InitMetrics(reg, "test")

	// SDP with Opus but no H264
	sdp := "v=0\r\na=rtpmap:111 opus/48000/2\r\n"
	e := echo.New()
	req := httptest.NewRequest(http.MethodPost, "/whep/cam", strings.NewReader(sdp))
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)
	c.SetParamNames("id")
	c.SetParamValues("cam")
	_ = h.Subscribe(c)

	if rec.Code != http.StatusNotAcceptable {
		t.Fatalf("expected 406, got %d", rec.Code)
	}

	n := testutil.ToFloat64(h.met.codecMismatches.WithLabelValues("cam", "h264"))
	if n != 1 {
		t.Fatalf("codec_mismatches{kind=h264}: want 1, got %v", n)
	}
}

// TestMetrics_Stats returns consistent snapshots at zero and with streams.
func TestMetrics_Stats(t *testing.T) {
	h, _ := newTestHandler(t)

	got := h.Stats()
	if got.StreamCount != 0 {
		t.Fatalf("expected 0 streams, got %d", got.StreamCount)
	}
	if got.UDPPortsInUse != 0 {
		t.Fatalf("expected 0 udp ports, got %d", got.UDPPortsInUse)
	}

	// Inject a stream to verify counts update
	h.sub.mu.Lock()
	h.sub.streams["test"] = &processStream{id: "test"}
	h.sub.mu.Unlock()

	got = h.Stats()
	if got.StreamCount != 1 {
		t.Fatalf("expected 1 stream, got %d", got.StreamCount)
	}
	if got.UDPPortsInUse != 2 {
		t.Fatalf("expected 2 udp ports, got %d", got.UDPPortsInUse)
	}
}
