package utils

import (
	"net"
	"testing"
	"time"

	"gopkg.in/yaml.v3"
)

func TestWaitForTCPPort_Success(t *testing.T) {
	// Start a TCP listener on a random port
	ln, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("failed to start listener: %v", err)
	}
	defer ln.Close()

	port := ln.Addr().(*net.TCPAddr).Port

	err = waitForTCPPort(port, 5*time.Second)
	if err != nil {
		t.Errorf("expected success, got error: %v", err)
	}
}

func TestWaitForTCPPort_Timeout(t *testing.T) {
	// Use a port that nothing is listening on
	ln, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("failed to get free port: %v", err)
	}
	port := ln.Addr().(*net.TCPAddr).Port
	ln.Close() // Close immediately so nothing is listening

	err = waitForTCPPort(port, 3*time.Second)
	if err == nil {
		t.Error("expected timeout error, got nil")
	}
}

func TestWaitForTCPPort_DelayedStart(t *testing.T) {
	// Get a free port
	ln, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("failed to get free port: %v", err)
	}
	port := ln.Addr().(*net.TCPAddr).Port
	ln.Close()

	// Start listening after a delay
	go func() {
		time.Sleep(2 * time.Second)
		newLn, err := net.Listen("tcp", ln.Addr().String())
		if err != nil {
			return
		}
		defer newLn.Close()
		// Keep it open long enough for the test
		time.Sleep(10 * time.Second)
	}()

	err = waitForTCPPort(port, 10*time.Second)
	if err != nil {
		t.Errorf("expected success after delayed start, got error: %v", err)
	}
}

func TestOlricConfigYAMLParsing(t *testing.T) {
	// Verify that the YAML parsing struct matches the format
	// generated by pkg/namespace/systemd_spawner.go
	configContent := `server:
  bindAddr: 10.0.0.1
  bindPort: 10002
memberlist:
  environment: lan
  bindAddr: 10.0.0.1
  bindPort: 10003
  peers:
    - 10.0.0.2:10003
partitionCount: 12
`

	var cfg struct {
		Memberlist struct {
			BindPort int `yaml:"bindPort"`
		} `yaml:"memberlist"`
	}

	if err := yaml.Unmarshal([]byte(configContent), &cfg); err != nil {
		t.Fatalf("failed to parse Olric config YAML: %v", err)
	}

	if cfg.Memberlist.BindPort != 10003 {
		t.Errorf("expected memberlist port 10003, got %d", cfg.Memberlist.BindPort)
	}
}

func TestOlricConfigYAMLParsing_MissingMemberlist(t *testing.T) {
	// Config without memberlist section should return zero port
	configContent := `server:
  bindAddr: 10.0.0.1
  bindPort: 10002
`

	var cfg struct {
		Memberlist struct {
			BindPort int `yaml:"bindPort"`
		} `yaml:"memberlist"`
	}

	if err := yaml.Unmarshal([]byte(configContent), &cfg); err != nil {
		t.Fatalf("unexpected parse error: %v", err)
	}

	if cfg.Memberlist.BindPort != 0 {
		t.Errorf("expected port 0 for missing memberlist, got %d", cfg.Memberlist.BindPort)
	}
}
