package storage

import (
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"nadir/internal/oscmd"

	"github.com/danielgtaylor/huma/v2"
	"github.com/danielgtaylor/huma/v2/adapters/humago"
	"github.com/danielgtaylor/huma/v2/humatest"
)

func TestStorageHandlers(t *testing.T) {
	path := filepath.Join(t.TempDir(), "fstab")
	if err := os.WriteFile(path, []byte("# seed\nUUID=root / ext4 defaults 0 1\n"), 0644); err != nil {
		t.Fatal(err)
	}
	old := fstabFile
	fstabFile = path
	defer func() { fstabFile = old }()

	mux := http.NewServeMux()
	api := humatest.Wrap(t, humago.New(mux, huma.DefaultConfig("Test", "1.0.0")))
	New().Register(api)

	mountOK := true
	oscmd.SetMock("mount", func([]string) oscmd.MockCommand {
		if mountOK {
			return oscmd.MockCommand{ExitCode: 0}
		}
		return oscmd.MockCommand{Stderr: "mount: wrong fs type", ExitCode: 32}
	})
	oscmd.SetMock("umount", func([]string) oscmd.MockCommand { return oscmd.MockCommand{ExitCode: 0} })
	defer oscmd.ClearMocks()

	body := map[string]any{"device": "/dev/sdb1", "mountpoint": "/mnt/data", "fstype": "ext4"}

	// Add + mount succeeds.
	if resp := api.Post("/api/storage/mounts", body); resp.Code != http.StatusOK {
		t.Fatalf("add mount: got %d, body=%s", resp.Code, resp.Body.String())
	}
	if findEntry(mustReadFstab(t), "/mnt/data") == nil {
		t.Fatal("entry not written to fstab")
	}

	// Duplicate mountpoint → 409.
	if resp := api.Post("/api/storage/mounts", body); resp.Code != http.StatusConflict {
		t.Errorf("duplicate: got %d, want 409", resp.Code)
	}

	// mount fails → 400 and the fstab line is rolled back.
	mountOK = false
	bad := map[string]any{"device": "/dev/sdc1", "mountpoint": "/mnt/bad", "fstype": "ext4"}
	if resp := api.Post("/api/storage/mounts", bad); resp.Code != http.StatusBadRequest {
		t.Errorf("failed mount: got %d, want 400", resp.Code)
	}
	if findEntry(mustReadFstab(t), "/mnt/bad") != nil {
		t.Error("fstab entry not rolled back after mount failure")
	}

	// Invalid device is rejected before touching the system.
	if resp := api.Post("/api/storage/mounts", map[string]any{"device": "/dev/x; rm", "mountpoint": "/mnt/x", "fstype": "ext4"}); resp.Code != http.StatusBadRequest {
		t.Errorf("invalid device: got %d, want 400", resp.Code)
	}

	// Delete the good entry (not actually mounted, so no umount needed).
	if resp := api.Delete("/api/storage/mounts?mountpoint=/mnt/data"); resp.Code != http.StatusOK {
		t.Errorf("delete: got %d, body=%s", resp.Code, resp.Body.String())
	}
	data, _ := os.ReadFile(path)
	if strings.Contains(string(data), "/mnt/data") || !strings.Contains(string(data), "# seed") {
		t.Errorf("delete result wrong:\n%s", data)
	}

	// Deleting a nonexistent mountpoint → 404.
	if resp := api.Delete("/api/storage/mounts?mountpoint=/mnt/none"); resp.Code != http.StatusNotFound {
		t.Errorf("delete missing: got %d, want 404", resp.Code)
	}
}
