package cli

import (
	"strings"
	"testing"
)

// TestLabProfiles_WellFormed guards the --lab registry: every bundled target
// must be fully wired (map key == name, non-empty compose/target/scope/readyURL,
// positive timeouts) and resolvable. Adding a target without these trips here.
func TestLabProfiles_WellFormed(t *testing.T) {
	if len(labProfiles) == 0 {
		t.Fatal("no lab profiles registered")
	}
	for key, p := range labProfiles {
		if p.name != key {
			t.Errorf("labProfiles[%q].name = %q (map key and name must match)", key, p.name)
		}
		if strings.TrimSpace(p.compose) == "" || !strings.Contains(p.compose, "services:") {
			t.Errorf("%s: compose is empty or not a compose file", key)
		}
		if p.target == "" || !strings.HasPrefix(p.target, "http") {
			t.Errorf("%s: target must be an http(s) URL, got %q", key, p.target)
		}
		if p.readyURL == "" || !strings.HasPrefix(p.readyURL, "http") {
			t.Errorf("%s: readyURL must be an http(s) URL, got %q", key, p.readyURL)
		}
		if p.scope == "" {
			t.Errorf("%s: empty scope", key)
		}
		if p.upTimeout <= 0 || p.readyTimeout <= 0 {
			t.Errorf("%s: non-positive timeouts", key)
		}
		got, err := resolveLabProfile(key)
		if err != nil || got.name != key {
			t.Errorf("resolveLabProfile(%q) = %+v, %v", key, got, err)
		}
	}
}

// TestLabProfiles_ExpectedTargetsPresent pins the set so a regression that drops
// a Black Hat Arsenal target is caught.
func TestLabProfiles_ExpectedTargetsPresent(t *testing.T) {
	for _, want := range []string{"juiceshop", "crapi", "vampi", "dvga", "dvwa", "webgoat", "bwapp", "mutillidae"} {
		if _, ok := labProfiles[want]; !ok {
			t.Errorf("expected --lab target %q to be registered", want)
		}
	}
}

func TestResolveLabProfile_Unknown(t *testing.T) {
	if _, err := resolveLabProfile("does-not-exist"); err == nil {
		t.Error("unknown --lab-target should error")
	}
}

// TestHostPortsFromCompose checks the pre-flight port parser handles every
// mapping form the bundled labs use (bind-address, host:container, bare).
func TestHostPortsFromCompose(t *testing.T) {
	compose := `services:
  web:
    ports:
      - "127.0.0.1:8025:8025"
      - "8888:80"
      - 127.0.0.1:30080:80
      - "3000:3000"
      - "127.0.0.1:8025:8025"`
	got := hostPortsFromCompose(compose)
	want := []string{"8025", "8888", "30080", "3000"} // deduped, in order
	if len(got) != len(want) {
		t.Fatalf("hostPortsFromCompose = %v, want %v", got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Errorf("port[%d] = %q, want %q", i, got[i], want[i])
		}
	}
}

// TestLabProjectName pins the stable per-target project name so re-runs
// reconcile the same stack instead of colliding.
func TestLabProjectName(t *testing.T) {
	if got := labProjectName("crapi"); got != "pentestswarm-lab-crapi" {
		t.Errorf("labProjectName(crapi) = %q", got)
	}
}
