package integration

import (
	"context"
	"testing"
	"time"

	"git.cloudinit.dev/coreci/orca/internal/model"
	"git.cloudinit.dev/coreci/orca/internal/paths"
)

func TestHarness_CreatesValidOrcaHome(t *testing.T) {
	h := NewHarness(t)
	if h.Home == "" {
		t.Fatal("Home is empty")
	}
	if h.DB == nil {
		t.Fatal("DB is nil")
	}
	if h.Registry == nil {
		t.Fatal("Registry is nil")
	}
	if err := h.VerifyState(); err != nil {
		t.Fatalf("VerifyState: %v", err)
	}
	ctx := context.Background()
	nodes, err := h.Registry.List(ctx)
	if err != nil {
		t.Fatalf("List nodes: %v", err)
	}
	if len(nodes) != 1 || nodes[0].Name != "localhost" {
		t.Errorf("expected localhost node, got %+v", nodes)
	}
}

func TestHarness_MasterKeyMode(t *testing.T) {
	h := NewHarness(t)
	if err := h.VerifyState(); err != nil {
		t.Fatalf("VerifyState: %v", err)
	}
	info, err := statPerm(paths.MasterKeyPath())
	if err != nil {
		t.Fatalf("stat master key: %v", err)
	}
	const want = 0o600
	if info != want {
		t.Errorf("master key mode %o, want %o", info, want)
	}
}

func TestHarness_MockPeerRecordsCommands(t *testing.T) {
	h := NewHarness(t)
	peer := h.RegisterPeer("node-a", "node-a:22")
	peer.SetRunning("alloc-1", "alloc-2")

	ctx := context.Background()
	running, err := h.ListAllocs(ctx, "node-a")
	if err != nil {
		t.Fatalf("ListAllocs: %v", err)
	}
	if len(running) != 2 {
		t.Errorf("running allocs = %v, want 2", running)
	}
	cmds := peer.Commands()
	if len(cmds) < 1 {
		t.Fatalf("expected recorded commands, got %v", cmds)
	}
	foundList := false
	for _, c := range cmds {
		if startsWith(c, "systemctl list-units 'orca-alloc-*.service'") {
			foundList = true
		}
	}
	if !foundList {
		t.Errorf("no list-units command recorded: %v", cmds)
	}
}

func TestHarness_DrainNodeStopsAllocs(t *testing.T) {
	h := NewHarness(t)
	peer := h.RegisterPeer("node-b", "node-b:22")
	peer.SetRunning("alloc-x", "alloc-y")

	ctx := context.Background()
	stopped, err := h.DrainNode(ctx, "node-b")
	if err != nil {
		t.Fatalf("DrainNode: %v", err)
	}
	if len(stopped) != 2 {
		t.Errorf("stopped = %v, want 2", stopped)
	}
	if r := peer.RunningAllocs(); len(r) != 0 {
		t.Errorf("after drain, running = %v, want empty", r)
	}
	nodes, err := h.Registry.List(ctx)
	if err != nil {
		t.Fatalf("List: %v", err)
	}
	for _, n := range nodes {
		if n.Name == "node-b" && n.State != model.NodeStateDrained {
			t.Errorf("node-b state = %q, want drained", n.State)
		}
	}
}

func TestHarness_SubmitJobHelperWorks(t *testing.T) {
	h := NewHarness(t)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	jobID, err := h.SubmitJob(ctx, "smoke", "/bin/true")
	if err != nil {
		t.Fatalf("SubmitJob: %v", err)
	}
	if jobID == "" {
		t.Fatal("SubmitJob returned empty id")
	}
	jobs, err := h.Jobs.List(ctx)
	if err != nil {
		t.Fatalf("Jobs.List: %v", err)
	}
	var found bool
	for _, j := range jobs {
		if j.ID == jobID && j.Status == model.JobStatusComplete {
			found = true
		}
	}
	if !found {
		t.Errorf("submitted job %s not complete in list: %+v", jobID, jobs)
	}
}

func TestHarness_MockTransportUnknownPeerErrors(t *testing.T) {
	h := NewHarness(t)
	ctx := context.Background()
	if _, err := h.Transport.Exec(ctx, "ghost", "true"); err == nil {
		t.Error("expected error for unknown peer, got nil")
	}
}
