package infra

import (
	"strings"
	"testing"
)

func sampleSambaData() SambaData {
	return SambaData{
		ServerName: "FELHOM",
		UID:        1000,
		Shares: []SambaShareRender{
			{Name: "dokumentumok", Path: "/mnt/felhom-drives/scratch1/shares/dokumentumok", ReadOnly: false},
			{Name: "filmek", Path: "/mnt/felhom-drives/media/filmek", ReadOnly: true},
		},
	}
}

// Exact golden for smb.conf (§10): the hardened global block + one section per share, in registry
// order, with the force-user block. A drift in any managed directive fails here.
func TestRenderSambaConfig_Golden(t *testing.T) {
	const want = `# Samba (LAN network-sharing) — managed by felhom-controller (R-7).
# WARNING: auto-generated. Manual edits are overwritten on the next share change.
[global]
  workgroup = WORKGROUP
  server string = Felhom hálózati megosztás
  netbios name = FELHOM
  security = user
  map to guest = never
  server min protocol = SMB2
  disable netbios = no
  bind interfaces only = yes
  interfaces = lo eth0
  smb ports = 445
  load printers = no
  printing = bsd
  printcap name = /dev/null
  disable spoolss = yes

[dokumentumok]
  path = /mnt/felhom-drives/scratch1/shares/dokumentumok
  read only = no
  valid users = felhom
  force user = felhom
  force group = felhom
  create mask = 0644
  directory mask = 0755

[filmek]
  path = /mnt/felhom-drives/media/filmek
  read only = yes
  valid users = felhom
  force user = felhom
  force group = felhom
  create mask = 0644
  directory mask = 0755
`
	got := RenderSambaConfig(sampleSambaData())
	if got != want {
		t.Errorf("smb.conf golden mismatch.\n--- got ---\n%s\n--- want ---\n%s", got, want)
	}
}

func TestRenderSambaConfig_NoShares(t *testing.T) {
	got := RenderSambaConfig(SambaData{ServerName: "OTTHON", UID: 1000})
	if !strings.Contains(got, "netbios name = OTTHON") {
		t.Error("server name not rendered")
	}
	if strings.Count(got, "[") != 1 { // only [global]
		t.Errorf("no shares should mean only the [global] section:\n%s", got)
	}
}

// Compose: host network + pinned image + config :ro + passdb volume, and — the Scenario B core — a
// read-only share gets a :ro bind while a writable one does not. Share binds are sorted (filmek<scratch1).
func TestRenderSambaCompose(t *testing.T) {
	got := RenderSambaCompose(sampleSambaData())
	for _, want := range []string{
		"network_mode: host",
		"image: " + SambaImage,
		"- ./smb.conf:/etc/samba/smb.conf:ro",
		"- samba-passdb:/var/lib/samba",
		"FELHOM_SERVER_NAME=FELHOM",
		"FELHOM_UID=1000",
	} {
		if !strings.Contains(got, want) {
			t.Errorf("compose missing %q\n%s", want, got)
		}
	}
	// The tag must be EXPLICIT — a floating :latest breaks reproducible pins and is the thing the
	// constant exists to prevent. Asserted on the constant's shape, so an image bump is a one-line
	// change in infra.go and never a test edit.
	if strings.HasSuffix(SambaImage, ":latest") || !strings.Contains(SambaImage, ":") {
		t.Errorf("SambaImage %q must carry an explicit non-latest tag", SambaImage)
	}

	// Read-only share → :ro bind (red-proof target: drop the :ro in the renderer and this fails).
	roBind := "- /mnt/felhom-drives/media/filmek:/mnt/felhom-drives/media/filmek:ro"
	if !strings.Contains(got, roBind) {
		t.Errorf("read-only share must get a :ro bind, missing %q\n%s", roBind, got)
	}
	// Writable share → plain bind, NOT :ro.
	rwBind := "- /mnt/felhom-drives/scratch1/shares/dokumentumok:/mnt/felhom-drives/scratch1/shares/dokumentumok\n"
	if !strings.Contains(got, rwBind) {
		t.Errorf("writable share must get a plain bind, missing %q\n%s", rwBind, got)
	}
	if strings.Contains(got, "/mnt/felhom-drives/scratch1/shares/dokumentumok:/mnt/felhom-drives/scratch1/shares/dokumentumok:ro") {
		t.Error("writable share must NOT be :ro")
	}
}
