package daemon

import (
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"os"
	"path/filepath"
	"strconv"
	"testing"

	"banger/internal/guest"
	"banger/internal/model"
)

func TestTapPoolWarmsAndReusesIdleTap(t *testing.T) {
	t.Parallel()

	runner := &scriptedRunner{
		t: t,
		steps: []runnerStep{
			{call: runnerCall{name: "ip", args: []string{"link", "show", "tap-pool-0"}}, err: errors.New("exit status 1")},
			sudoStep("", nil, "ip", "tuntap", "add", "dev", "tap-pool-0", "mode", "tap", "user", strconv.Itoa(os.Getuid()), "group", strconv.Itoa(os.Getgid())),
			sudoStep("", nil, "ip", "link", "set", "tap-pool-0", "master", model.DefaultBridgeName),
			sudoStep("", nil, "ip", "link", "set", "tap-pool-0", "up"),
			sudoStep("", nil, "ip", "link", "set", model.DefaultBridgeName, "up"),
		},
	}
	d := &Daemon{
		runner: runner,
		config: model.DaemonConfig{
			BridgeName:  model.DefaultBridgeName,
			TapPoolSize: 1,
		},
		closing: make(chan struct{}),
	}
	wireServices(d)

	d.net.ensureTapPool(context.Background())
	tapName, err := d.net.acquireTap(context.Background(), "tap-fallback")
	if err != nil {
		t.Fatalf("acquireTap: %v", err)
	}
	if tapName != "tap-pool-0" {
		t.Fatalf("tapName = %q, want tap-pool-0", tapName)
	}
	if err := d.net.releaseTap(context.Background(), tapName); err != nil {
		t.Fatalf("releaseTap: %v", err)
	}
	tapName, err = d.net.acquireTap(context.Background(), "tap-fallback")
	if err != nil {
		t.Fatalf("acquireTap second time: %v", err)
	}
	if tapName != "tap-pool-0" {
		t.Fatalf("tapName second = %q, want tap-pool-0", tapName)
	}
	runner.assertExhausted()
}

func TestEnsureAuthorizedKeyOnWorkDiskSkipsRepairForMatchingSeededFingerprint(t *testing.T) {
	t.Parallel()

	privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
	if err != nil {
		t.Fatalf("GenerateKey: %v", err)
	}
	privateKeyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
	})
	sshKeyPath := filepath.Join(t.TempDir(), "id_rsa")
	if err := os.WriteFile(sshKeyPath, privateKeyPEM, 0o600); err != nil {
		t.Fatalf("WriteFile(private key): %v", err)
	}
	fingerprint, err := guest.AuthorizedPublicKeyFingerprint(sshKeyPath)
	if err != nil {
		t.Fatalf("AuthorizedPublicKeyFingerprint: %v", err)
	}

	runner := &scriptedRunner{t: t}
	d := &Daemon{
		runner: runner,
		config: model.DaemonConfig{SSHKeyPath: sshKeyPath},
	}
	wireServices(d)
	vm := testVM("seeded-fastpath", "image-seeded-fastpath", "172.16.0.62")
	vm.Runtime.WorkDiskPath = filepath.Join(t.TempDir(), "root.ext4")
	image := model.Image{SeededSSHPublicKeyFingerprint: fingerprint}

	if err := d.ws.ensureAuthorizedKeyOnWorkDisk(context.Background(), &vm, image, workDiskPreparation{ClonedFromSeed: true}); err != nil {
		t.Fatalf("ensureAuthorizedKeyOnWorkDisk: %v", err)
	}
	runner.assertExhausted()
}
