package daemon

import (
	"context"
	"io"
	"log/slog"
	"path/filepath"
	"strings"
	"testing"

	"banger/internal/api"
	"banger/internal/model"
)

// newWorkspaceRejectionDaemon returns a running-VM + wired daemon
// suitable for the PrepareVMWorkspace rejection tests. No real guest
// state — rejection paths return before any SSH I/O, so the fake
// firecracker infra the happy-path tests need is unnecessary here.
func newWorkspaceRejectionDaemon(t *testing.T) (*Daemon, model.VMRecord) {
	t.Helper()
	vm := testVM("rejectbox", "image-reject", "172.16.0.211")
	vm.State = model.VMStateRunning
	vm.Runtime.State = model.VMStateRunning

	d := &Daemon{
		store:  openDaemonStore(t),
		config: model.DaemonConfig{SSHKeyPath: filepath.Join(t.TempDir(), "id_ed25519")},
		logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
	}
	wireServices(d)
	upsertDaemonVM(t, context.Background(), d.store, vm)
	// Handle cache entry with a live-looking PID so vmAlive returns
	// true for the "VM is running" path; the rejection tests that want
	// the not-running branch clear this override explicitly.
	d.vm.setVMHandlesInMemory(vm.ID, model.VMHandles{PID: 1}) // init is always alive
	return d, vm
}

func TestPrepareVMWorkspace_RejectsMalformedMode(t *testing.T) {
	d, vm := newWorkspaceRejectionDaemon(t)
	_, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{
		IDOrName:   vm.Name,
		SourcePath: "/tmp/fake",
		Mode:       "bogus_mode",
	})
	if err == nil || !strings.Contains(err.Error(), "unsupported workspace mode") {
		t.Fatalf("err = %v, want unsupported-mode rejection", err)
	}
}

func TestPrepareVMWorkspace_RejectsFromWithoutBranch(t *testing.T) {
	d, vm := newWorkspaceRejectionDaemon(t)
	_, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{
		IDOrName:   vm.Name,
		SourcePath: "/tmp/fake",
		From:       "HEAD",
		// Branch deliberately left empty.
	})
	if err == nil || !strings.Contains(err.Error(), "workspace from requires branch") {
		t.Fatalf("err = %v, want from-without-branch rejection", err)
	}
}

func TestPrepareVMWorkspace_RejectsNotRunningVM(t *testing.T) {
	d, vm := newWorkspaceRejectionDaemon(t)
	// Clear handles so vmAlive returns false — simulates a VM that's
	// been stopped or never booted.
	d.vm.clearVMHandles(vm)
	_, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{
		IDOrName:   vm.Name,
		SourcePath: "/tmp/fake",
	})
	if err == nil || !strings.Contains(err.Error(), "is not running") {
		t.Fatalf("err = %v, want not-running rejection", err)
	}
}

func TestPrepareVMWorkspace_RejectsUnknownVM(t *testing.T) {
	d, _ := newWorkspaceRejectionDaemon(t)
	_, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{
		IDOrName:   "ghost-vm",
		SourcePath: "/tmp/fake",
	})
	if err == nil || !strings.Contains(err.Error(), "not found") {
		t.Fatalf("err = %v, want VM-not-found rejection", err)
	}
}
