package groups

import (
	"encoding/json"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"nadir/internal/oscmd"

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

func TestGroupsHandlers(t *testing.T) {
	tempGroup := filepath.Join(t.TempDir(), "group")
	initialContent := "root:x:0:\nwheel:x:10:alice,bob\n"
	if err := os.WriteFile(tempGroup, []byte(initialContent), 0644); err != nil {
		t.Fatal(err)
	}

	oldGroup := groupPath
	groupPath = tempGroup
	defer func() { groupPath = oldGroup }()

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

	// 1. Test GET /api/groups
	resp := api.Get("/api/groups")
	if resp.Code != http.StatusOK {
		t.Errorf("list groups: got %d, want %d", resp.Code, http.StatusOK)
	}
	var listRes ListGroupsOutput
	if err := json.Unmarshal(resp.Body.Bytes(), &listRes.Body); err != nil {
		t.Fatal(err)
	}
	if len(listRes.Body.Groups) != 2 {
		t.Errorf("got %d groups, want 2", len(listRes.Body.Groups))
	}

	// 2. Test GET /api/groups/{group}
	resp = api.Get("/api/groups/wheel")
	if resp.Code != http.StatusOK {
		t.Errorf("get group: got %d, want %d", resp.Code, http.StatusOK)
	}
	var getRes GetGroupOutput
	if err := json.Unmarshal(resp.Body.Bytes(), &getRes.Body); err != nil {
		t.Fatal(err)
	}
	if getRes.Body.Name != "wheel" || getRes.Body.GID != 10 {
		t.Errorf("get group: got %+v", getRes.Body)
	}

	resp = api.Get("/api/groups/nonexistent")
	if resp.Code != http.StatusNotFound {
		t.Errorf("get non-existent group: got %d, want %d", resp.Code, http.StatusNotFound)
	}

	// 3. Test POST /api/groups
	oscmd.SetMock("groupadd", func(args []string) oscmd.MockCommand {
		wantArgs := []string{"-g", "1500", "--", "dev"}
		if !reflect.DeepEqual(args, wantArgs) {
			t.Errorf("groupadd args: got %v, want %v", args, wantArgs)
		}
		devContent := initialContent + "dev:x:1500:\n"
		os.WriteFile(tempGroup, []byte(devContent), 0644)
		return oscmd.MockCommand{ExitCode: 0}
	})
	defer oscmd.ClearMocks()

	gidVal := 1500
	resp = api.Post("/api/groups", struct {
		Name string `json:"name"`
		GID  *int   `json:"gid"`
	}{
		Name: "dev",
		GID:  &gidVal,
	})
	if resp.Code != http.StatusOK {
		t.Errorf("create group: got %d, want %d", resp.Code, http.StatusOK)
	}

	// 4. Test DELETE /api/groups/{group}
	oscmd.SetMock("groupdel", func(args []string) oscmd.MockCommand {
		wantArgs := []string{"--", "dev"}
		if !reflect.DeepEqual(args, wantArgs) {
			t.Errorf("groupdel args: got %v, want %v", args, wantArgs)
		}
		os.WriteFile(tempGroup, []byte(initialContent), 0644)
		return oscmd.MockCommand{ExitCode: 0}
	})

	resp = api.Delete("/api/groups/dev")
	if resp.Code != http.StatusOK {
		t.Errorf("delete group: got %d, want %d", resp.Code, http.StatusOK)
	}
}
