/*
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
:                                                                               :
:   █▀ █ █▀▀   ·   Blazing-fast pentesting suite                                :
:   ▄█ █ █▀    ·   BSD 3-Clause License                                         :
:                                                                               :
:   (c) 2022-2026 vmfunc, xyzeva,                                               :
:                 lunchcat alumni & contributors                                :
:                                                                               :
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
*/

package sif

import (
	"testing"

	"github.com/vmfunc/sif/internal/output"
)

// TestScanAllTargetsConcurrentIsolation runs the target pool at concurrency 3
// against three separate servers and asserts each target's result is isolated:
// exactly one scan recorded per target, results in input order. Run under -race
// it also backstops scanTarget's concurrency safety and the serialized sink.
func TestScanAllTargetsConcurrentIsolation(t *testing.T) {
	defer output.SetConcurrent(false)

	srvA := okServer()
	defer srvA.Close()
	srvB := okServer()
	defer srvB.Close()
	srvC := okServer()
	defer srvC.Close()

	app := headersOnlyApp()
	app.targets = []string{srvA.URL, srvB.URL, srvC.URL}
	app.settings.Concurrency = 3

	results, err := app.scanAllTargets("", false)
	if err != nil {
		t.Fatalf("scanAllTargets: %v", err)
	}
	if len(results) != len(app.targets) {
		t.Fatalf("got %d results, want %d", len(results), len(app.targets))
	}
	for i, ts := range results {
		if len(ts.scansRun) != 1 || ts.scansRun[0] != "HTTP Headers" {
			t.Errorf("target %d scansRun = %v, want exactly [HTTP Headers] (accumulator leaked across targets)", i, ts.scansRun)
		}
	}
}

// TestScanAllTargetsSequentialMatchesInputOrder pins that concurrency 1 keeps the
// plain sequential path: one result per target, in order, no pool engaged.
func TestScanAllTargetsSequentialMatchesInputOrder(t *testing.T) {
	srvA := okServer()
	defer srvA.Close()
	srvB := okServer()
	defer srvB.Close()

	app := headersOnlyApp()
	app.targets = []string{srvA.URL, srvB.URL}
	app.settings.Concurrency = 1

	results, err := app.scanAllTargets("", false)
	if err != nil {
		t.Fatalf("scanAllTargets: %v", err)
	}
	if len(results) != 2 {
		t.Fatalf("got %d results, want 2", len(results))
	}
	for i, ts := range results {
		if len(ts.scansRun) != 1 || ts.scansRun[0] != "HTTP Headers" {
			t.Errorf("target %d scansRun = %v, want exactly [HTTP Headers]", i, ts.scansRun)
		}
	}
	if output.Concurrent() {
		t.Error("concurrency 1 must not switch output into concurrent mode")
	}
}
