package module

import (
	"path/filepath"
	"testing"
	"time"
)

// TestLoad7DTDManifest loads the real 7 Days to Die manifest shipped in
// modules/7dtd and asserts the panel-critical fields parsed correctly.
// Keeping this coupled to the real file (rather than a testdata copy) means
// changes to the shipped manifest must keep the test green.
func TestLoad7DTDManifest(t *testing.T) {
	path := filepath.Join("..", "..", "modules", "7dtd", "module.yaml")
	m, err := LoadFile(path)
	if err != nil {
		t.Fatalf("LoadFile: %v", err)
	}

	if m.ID != "7dtd" {
		t.Errorf("id = %q, want 7dtd", m.ID)
	}
	if !m.HasMode("docker") {
		t.Errorf("expected docker mode, got %v", m.SupportedModes)
	}
	if m.Runtime.Docker == nil || m.Runtime.Docker.Image == "" {
		t.Error("expected docker runtime with image")
	}
	if m.RCON == nil || m.RCON.Adapter != "telnet" {
		t.Errorf("rcon adapter = %+v, want telnet", m.RCON)
	}
	if p := m.Port("telnet"); p == nil || p.Proto != "tcp" || !p.Internal {
		t.Errorf("telnet port malformed: %+v", p)
	}
	if up := m.UpdateProvider("stable"); up == nil || up.Kind != "steamcmd" || up.AppID != "294420" {
		t.Errorf("stable update provider malformed: %+v", up)
	}
	if len(m.Events) < 3 {
		t.Errorf("expected at least join/leave/chat events, got %d", len(m.Events))
	}
	// state_sources[0] should be rcon poll with a 30s cadence
	if len(m.StateSources) == 0 {
		t.Fatal("expected at least one state source")
	}
	ss := m.StateSources[0]
	if ss.Type != "rcon" || ss.Command != "lp" {
		t.Errorf("first state source = %+v, want rcon lp", ss)
	}
	if ss.Every.Std() != 30*time.Second {
		t.Errorf("state source every = %v, want 30s", ss.Every.Std())
	}
}

func TestLoadDirSkipsDirWithoutManifest(t *testing.T) {
	// modules/ has 7dtd + minecraft-java + valheim dirs, but only 7dtd has a
	// module.yaml right now. Loader should return 1 module.
	dir := filepath.Join("..", "..", "modules")
	ms, err := LoadDir(dir)
	if err != nil {
		t.Fatalf("LoadDir: %v", err)
	}
	if len(ms) < 1 {
		t.Errorf("want >= 1 modules, got %d", len(ms))
	}
	found := false
	for _, m := range ms {
		if m.ID == "7dtd" {
			found = true
		}
	}
	if !found {
		t.Error("7dtd not present in LoadDir result")
	}
}

func TestValidateRejectsMissingID(t *testing.T) {
	m := &Manifest{}
	if err := m.Validate(); err == nil {
		t.Error("expected validation error for empty manifest")
	}
}
