package stacks

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

	"gitea.dooplex.hu/admin/felhom-controller/internal/appbackup"
	"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)

// Scenario D: the shares registry drives samba's backup classification, and the resulting binds flow
// through the REAL ComputeCaptureSet tier filter — mandatory lands in BOTH offsite and tier-2,
// optional in tier-2 ONLY. No backup-engine internals are touched by this test or by the code.
func TestSambaClassifiedBinds_TierMembership(t *testing.T) {
	m, sett, root, _ := newSambaManager(t)
	storageRoot := filepath.Join(root, "drive")

	// Two shares under one registered storage root: one with Felhőmentés ON, one OFF.
	docs := filepath.Join(storageRoot, "shares", "dokumentumok")
	films := filepath.Join(storageRoot, "shares", "filmek")
	for _, d := range []string{docs, films} {
		if err := os.MkdirAll(d, 0o755); err != nil {
			t.Fatal(err)
		}
	}
	if err := sett.AddStoragePath(settings.StoragePath{Path: storageRoot, Schedulable: true}); err != nil {
		t.Fatal(err)
	}
	if err := sett.AddSMBShare(settings.SMBShare{Name: "dokumentumok", Path: docs, Offsite: true}); err != nil {
		t.Fatal(err)
	}
	if err := sett.AddSMBShare(settings.SMBShare{Name: "filmek", Path: films, Offsite: false}); err != nil {
		t.Fatal(err)
	}

	binds, has := m.ClassifiedBinds(SambaStackName)
	if !has {
		t.Fatal("samba must report a classification")
	}
	if len(binds) != 2 {
		t.Fatalf("expected 2 classified binds, got %d: %+v", len(binds), binds)
	}

	byRel := map[string]appbackup.BindClass{}
	for _, b := range binds {
		byRel[b.RelPath] = b.Class
	}
	if got := byRel["shares/dokumentumok"]; got != appbackup.ClassMandatory {
		t.Errorf("Felhőmentés ON must be mandatory, got %q", got)
	}
	if got := byRel["shares/filmek"]; got != appbackup.ClassOptional {
		t.Errorf("Felhőmentés OFF must be optional, got %q", got)
	}

	// Tier membership through the real helper.
	offsite := appbackup.ComputeCaptureSet(binds, has, appbackup.TierOffsite, storageRoot)
	secondary := appbackup.ComputeCaptureSet(binds, has, appbackup.TierSecondary, storageRoot)

	if !hasRel(offsite, "shares/dokumentumok") {
		t.Errorf("mandatory share must be in the OFFSITE set: %+v", offsite.Paths)
	}
	// The negative half — the part a broken mapping would silently flip.
	if hasRel(offsite, "shares/filmek") {
		t.Errorf("optional share must NOT be in the offsite set: %+v", offsite.Paths)
	}
	if !hasRel(secondary, "shares/dokumentumok") || !hasRel(secondary, "shares/filmek") {
		t.Errorf("tier-2 must carry BOTH mandatory and optional: %+v", secondary.Paths)
	}
}

func hasRel(cs appbackup.CaptureSet, rel string) bool {
	for _, p := range cs.Paths {
		if filepath.ToSlash(p.RelPath) == rel {
			return true
		}
	}
	return false
}

// The smb.conf / passdb mounts are config, not customer data — they must never be classified.
func TestSambaClassifiedBinds_ExcludesConfigMounts(t *testing.T) {
	m, sett, root, _ := newSambaManager(t)
	shareDir := seedShare(t, sett, root, "dokumentumok")
	if err := sett.AddSMBShare(settings.SMBShare{Name: "dokumentumok", Path: shareDir, Offsite: true}); err != nil {
		t.Fatal(err)
	}
	binds, has := m.ClassifiedBinds(SambaStackName)
	if !has {
		t.Fatal("expected classification")
	}
	for _, b := range binds {
		if strings.Contains(b.RelPath, "smb.conf") || strings.Contains(b.RelPath, "samba-passdb") ||
			strings.Contains(b.RelPath, "/var/lib/samba") {
			t.Errorf("config/passdb mount must not be classified: %+v", b)
		}
	}
	if len(binds) != 1 {
		t.Errorf("only the share should be classified, got %d binds: %+v", len(binds), binds)
	}
}

// No shares → an empty (but present) classification; never a nil/false that would read as "legacy".
func TestSambaClassifiedBinds_NoShares(t *testing.T) {
	m, _, _, _ := newSambaManager(t)
	binds, has := m.ClassifiedBinds(SambaStackName)
	if !has {
		t.Error("samba must always report a classification, even with no shares")
	}
	if len(binds) != 0 {
		t.Errorf("expected no binds, got %+v", binds)
	}
}
