package main

import (
	"os/user"
	"testing"
)

func TestParseCIFSMountEntries(t *testing.T) {
	contents := `# comment
UUID=1234 / ext4 defaults 0 1
//fileserver/media /mnt/media cifs username=alice,password=p@\040ss\,word,iocharset=utf8,uid=1000,gid=1000,file_mode=0664,dir_mode=0775,rw 0 0
//nas/backups /srv/backups smbfs username=bob,password=secret,noauto,ro 0 0
`

	entries := parseCIFSMountEntries(contents)
	if len(entries) != 2 {
		t.Fatalf("expected 2 CIFS entries, got %d", len(entries))
	}

	if entries[0].LineIndex != 2 {
		t.Fatalf("unexpected first line index: %d", entries[0].LineIndex)
	}
	if entries[0].Source != "//fileserver/media" {
		t.Fatalf("unexpected first source: %q", entries[0].Source)
	}
	if entries[0].MountPoint != "/mnt/media" {
		t.Fatalf("unexpected first mount point: %q", entries[0].MountPoint)
	}
	if entries[1].FSType != "smbfs" {
		t.Fatalf("unexpected second fs type: %q", entries[1].FSType)
	}
}

func TestCIFSMountConfigFromEntry(t *testing.T) {
	entry, ok := parseFstabMountLine("//fileserver/media /mnt/media cifs username=alice,password=p@\\040ss\\,word,domain=WORKGROUP,uid=1000,gid=1000,file_mode=0664,dir_mode=0775,noauto,ro 0 0", 0)
	if !ok {
		t.Fatal("expected line to parse")
	}

	cfg, ok := cifsMountConfigFromEntry(entry)
	if !ok {
		t.Fatal("expected config conversion to succeed")
	}

	if cfg.Server != "fileserver" || cfg.Share != "media" {
		t.Fatalf("unexpected source parsing: %+v", cfg)
	}
	if cfg.Password != "p@ ss,word" {
		t.Fatalf("unexpected password: %q", cfg.Password)
	}
	if cfg.Domain != "WORKGROUP" {
		t.Fatalf("unexpected domain: %q", cfg.Domain)
	}
	if cfg.AutoMount {
		t.Fatal("expected noauto to disable automount")
	}
	if !cfg.ReadOnly {
		t.Fatal("expected ro to set read-only")
	}
}

func TestUpdateFstabContentsAddEditDelete(t *testing.T) {
	initial := "# header\nUUID=1234 / ext4 defaults 0 1\n//old/share /mnt/share cifs username=old,password=old,rw 0 0\n"

	added, err := updateFstabContents(initial, "//new/share /mnt/new cifs username=new,password=new,rw 0 0", -1)
	if err != nil {
		t.Fatalf("add entry: %v", err)
	}
	wantAdded := "# header\nUUID=1234 / ext4 defaults 0 1\n//old/share /mnt/share cifs username=old,password=old,rw 0 0\n//new/share /mnt/new cifs username=new,password=new,rw 0 0\n"
	if added != wantAdded {
		t.Fatalf("unexpected add result:\nwant: %q\ngot:  %q", wantAdded, added)
	}

	edited, err := updateFstabContents(initial, "//old/share /mnt/share cifs username=alice,password=secret,ro 0 0", 2)
	if err != nil {
		t.Fatalf("edit entry: %v", err)
	}
	wantEdited := "# header\nUUID=1234 / ext4 defaults 0 1\n//old/share /mnt/share cifs username=alice,password=secret,ro 0 0\n"
	if edited != wantEdited {
		t.Fatalf("unexpected edit result:\nwant: %q\ngot:  %q", wantEdited, edited)
	}

	deleted, err := updateFstabContents(initial, "", 2)
	if err != nil {
		t.Fatalf("delete entry: %v", err)
	}
	wantDeleted := "# header\nUUID=1234 / ext4 defaults 0 1\n"
	if deleted != wantDeleted {
		t.Fatalf("unexpected delete result:\nwant: %q\ngot:  %q", wantDeleted, deleted)
	}
}

func TestDefaultLocalMountOwnerGroupUsesCurrentUser(t *testing.T) {
	getenv := func(string) string { return "" }
	currentUser := func() (*user.User, error) {
		return &user.User{Username: "alice", Gid: "1000"}, nil
	}
	lookupUser := func(string) (*user.User, error) {
		t.Fatal("lookupUser should not be called without SUDO_USER")
		return nil, nil
	}
	lookupGroupID := func(id string) (*user.Group, error) {
		if id != "1000" {
			t.Fatalf("unexpected group id lookup: %q", id)
		}
		return &user.Group{Name: "alice"}, nil
	}

	uid, gid := defaultLocalMountOwnerGroup(getenv, currentUser, lookupUser, lookupGroupID)
	if uid != "alice" || gid != "alice" {
		t.Fatalf("unexpected defaults: uid=%q gid=%q", uid, gid)
	}
}

func TestDefaultLocalMountOwnerGroupUsesSudoUser(t *testing.T) {
	getenv := func(key string) string {
		switch key {
		case "SUDO_USER":
			return "carol"
		case "SUDO_GID":
			return "2000"
		default:
			return ""
		}
	}
	currentUser := func() (*user.User, error) {
		return &user.User{Username: "root", Gid: "0"}, nil
	}
	lookupUser := func(string) (*user.User, error) {
		t.Fatal("lookupUser should not be called when SUDO_GID is set")
		return nil, nil
	}
	lookupGroupID := func(id string) (*user.Group, error) {
		if id != "2000" {
			t.Fatalf("unexpected group id lookup: %q", id)
		}
		return &user.Group{Name: "developers"}, nil
	}

	uid, gid := defaultLocalMountOwnerGroup(getenv, currentUser, lookupUser, lookupGroupID)
	if uid != "carol" || gid != "developers" {
		t.Fatalf("unexpected defaults: uid=%q gid=%q", uid, gid)
	}
}
