package exploit

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

	"github.com/Armur-Ai/Pentest-Swarm-AI/internal/swarm/verify"
	"github.com/Armur-Ai/Pentest-Swarm-AI/internal/swarm/verify/oracle"
)

func TestLDAPInjectionSpec_Shape(t *testing.T) {
	spec, err := LDAPInjectionSpec("https://t/users/ldap-search?user=bob", "user", "")
	if err != nil {
		t.Fatal(err)
	}
	if spec.Class != verify.ProbeDifferential || !spec.Valid() {
		t.Fatalf("invalid differential spec: %+v", spec)
	}
	if spec.AttackPayload != "*" || !strings.Contains(spec.ControlPayload, "nx_") {
		t.Errorf("payloads attack=%q control=%q", spec.AttackPayload, spec.ControlPayload)
	}
	if !strings.Contains(spec.BaseRequest, "user="+verify.DefaultMarker) {
		t.Errorf("param not marked: %q", spec.BaseRequest)
	}
}

func TestLDAPInjectionSpec_RejectsEmptyParam(t *testing.T) {
	if _, err := LDAPInjectionSpec("https://t/s", "", ""); err == nil {
		t.Error("empty param should be rejected")
	}
}

func TestLDAPInjectionSpecs_CoversCommonParams(t *testing.T) {
	specs, err := LDAPInjectionSpecs("https://t/ldap-search", "")
	if err != nil {
		t.Fatal(err)
	}
	if len(specs) != len(commonLDAPParams) {
		t.Fatalf("got %d specs, want %d", len(specs), len(commonLDAPParams))
	}
}

// End to end: a directory search that returns all entries for "*" but none for a
// specific miss is proven via the differential oracle (body divergence).
func TestLDAPInjectionSpec_ProvesViaDifferentialOracle(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		u := r.URL.Query().Get("user")
		w.WriteHeader(200)
		if strings.Contains(u, "*") { // filter (uid=*) matches everyone
			_, _ = w.Write([]byte(`{"results":["alice","bob","carol","dave","admin"]}`))
			return
		}
		_, _ = w.Write([]byte(`{"results":[]}`))
	}))
	defer srv.Close()

	spec, err := LDAPInjectionSpec(srv.URL+"/ldap-search?user=x", "user", "")
	if err != nil {
		t.Fatal(err)
	}
	v, _, proof, err := oracle.NewDifferential(oracle.LiveDiffProbe(srv.Client())).
		Probe(context.Background(), verify.Candidate{Target: srv.URL, Spec: spec})
	if err != nil || v != verify.Proven {
		t.Fatalf("verdict=%v err=%v proof=%q, want proven", v, err, proof)
	}
}
