package parser

import (
	"strings"
	"testing"
)

func TestIsHTTP1RequestTrue(t *testing.T) {
	cases := [][]byte{
		[]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"),
		[]byte("POST /api/data HTTP/1.1\r\n"),
		[]byte("PUT /resource HTTP/1.0\r\n"),
		[]byte("HEAD /ping HTTP/1.1\r\n"),
		[]byte("DELETE /item/1 HTTP/1.1\r\n"),
	}
	for _, c := range cases {
		if !IsHTTP1Request(c) {
			t.Errorf("attendu true pour %q", c[:20])
		}
	}
}

func TestIsHTTP1RequestFalse(t *testing.T) {
	cases := [][]byte{
		[]byte("HTTP/1.1 200 OK\r\n"),
		[]byte(H2Magic),
		[]byte("INVALID /path HTTP/1.1\r\n"),
		[]byte{0x16, 0x03, 0x01}, // TLS handshake
	}
	for _, c := range cases {
		if IsHTTP1Request(c) {
			t.Errorf("attendu false pour %q", c[:min(20, len(c))])
		}
	}
}

func TestParseHTTP1RequestBasic(t *testing.T) {
	raw := "GET /path/to/resource HTTP/1.1\r\n" +
		"Host: example.com\r\n" +
		"User-Agent: Go-http-client/1.1\r\n" +
		"Accept: */*\r\n" +
		"\r\n"
	req := ParseHTTP1Request([]byte(raw))
	if req == nil {
		t.Fatal("attendu non-nil")
	}
	if req.Method != "GET" {
		t.Errorf("method: attendu GET, obtenu %q", req.Method)
	}
	if req.Path != "/path/to/resource" {
		t.Errorf("path: %q", req.Path)
	}
	if req.Protocol != "HTTP/1.1" {
		t.Errorf("protocol: %q", req.Protocol)
	}
	if len(req.Headers) != 3 {
		t.Errorf("nb headers: attendu 3, obtenu %d", len(req.Headers))
	}
	if req.Headers[0] != "Host" {
		t.Errorf("premier header: attendu Host, obtenu %q", req.Headers[0])
	}
	expected := "Host;User-Agent;Accept"
	if req.HeaderSig != expected {
		t.Errorf("HeaderSig: attendu %q, obtenu %q", expected, req.HeaderSig)
	}
}

func TestParseHTTP1RequestWithQueryString(t *testing.T) {
	raw := "GET /search?q=ebpf&page=2 HTTP/1.1\r\nHost: test.com\r\n\r\n"
	req := ParseHTTP1Request([]byte(raw))
	if req == nil {
		t.Fatal("attendu non-nil")
	}
	if req.Path != "/search" {
		t.Errorf("path: attendu /search, obtenu %q", req.Path)
	}
	if req.Query != "q=ebpf&page=2" {
		t.Errorf("query: %q", req.Query)
	}
}

func TestParseHTTP1RequestHTTP10(t *testing.T) {
	raw := "GET / HTTP/1.0\r\nHost: legacy.com\r\n\r\n"
	req := ParseHTTP1Request([]byte(raw))
	if req == nil {
		t.Fatal("attendu non-nil")
	}
	if req.Protocol != "HTTP/1.0" {
		t.Errorf("protocol: %q", req.Protocol)
	}
}

func TestParseHTTP1RequestPostBody(t *testing.T) {
	raw := "POST /api/submit HTTP/1.1\r\n" +
		"Host: api.example.com\r\n" +
		"Content-Type: application/json\r\n" +
		"Content-Length: 42\r\n" +
		"\r\n" +
		`{"key":"value"}`
	req := ParseHTTP1Request([]byte(raw))
	if req == nil {
		t.Fatal("attendu non-nil")
	}
	if req.Method != "POST" {
		t.Errorf("method: %q", req.Method)
	}
	if len(req.Headers) != 3 {
		t.Errorf("nb headers: attendu 3, obtenu %d", len(req.Headers))
	}
}

func TestParseHTTP1RequestInvalid(t *testing.T) {
	cases := [][]byte{
		[]byte("HTTP/1.1 200 OK\r\n"),
		[]byte("NOTAMETHOD /path HTTP/1.1\r\n"),
		[]byte(""),
		{0xFF, 0xFE, 0xFD},
	}
	for _, c := range cases {
		req := ParseHTTP1Request(c)
		if req != nil {
			t.Errorf("attendu nil pour %q, obtenu non-nil", c)
		}
	}
}

func TestIsHTTP1Response(t *testing.T) {
	if !IsHTTP1Response([]byte("HTTP/1.1 200 OK\r\n")) {
		t.Error("attendu true pour HTTP/1.1 200")
	}
	if !IsHTTP1Response([]byte("HTTP/1.0 404 Not Found\r\n")) {
		t.Error("attendu true pour HTTP/1.0 404")
	}
	if IsHTTP1Response([]byte("GET / HTTP/1.1\r\n")) {
		t.Error("attendu false pour une requête")
	}
}

func TestParseHTTP1Response(t *testing.T) {
	cases := []struct {
		raw  string
		code int
	}{
		{"HTTP/1.1 200 OK\r\n", 200},
		{"HTTP/1.0 404 Not Found\r\n", 404},
		{"HTTP/1.1 301 Moved Permanently\r\n", 301},
		{"HTTP/1.1 500 Internal Server Error\r\n", 500},
	}
	for _, tc := range cases {
		resp := ParseHTTP1Response([]byte(tc.raw))
		if resp == nil {
			t.Errorf("attendu non-nil pour %q", tc.raw)
			continue
		}
		if resp.StatusCode != tc.code {
			t.Errorf("code attendu %d, obtenu %d pour %q", tc.code, resp.StatusCode, tc.raw)
		}
	}
}

func TestParseHTTP1ResponseInvalid(t *testing.T) {
	cases := []string{
		"GET / HTTP/1.1",
		"HTTP/1.1 99 Continue",  // hors plage 100-599
		"",
	}
	for _, tc := range cases {
		resp := ParseHTTP1Response([]byte(tc))
		if resp != nil && (resp.StatusCode < 100 || resp.StatusCode > 599) {
			t.Errorf("code invalide %d pour %q", resp.StatusCode, tc)
		}
	}
}

// min retourne le minimum de deux entiers (helper pour les tests).
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func TestHTTP1HeaderOrderSignature(t *testing.T) {
	raw := "GET / HTTP/1.1\r\n" +
		"Accept: text/html\r\n" +
		"Accept-Encoding: gzip\r\n" +
		"Connection: keep-alive\r\n" +
		"Host: example.com\r\n" +
		"\r\n"
	req := ParseHTTP1Request([]byte(raw))
	if req == nil {
		t.Fatal("attendu non-nil")
	}
	parts := strings.Split(req.HeaderSig, ";")
	if len(parts) != 4 {
		t.Errorf("attendu 4 headers dans la signature, obtenu %d: %q", len(parts), req.HeaderSig)
	}
	if parts[0] != "Accept" {
		t.Errorf("premier header sig: attendu Accept, obtenu %q", parts[0])
	}
}
