package zddc

import (
	"archive/zip"
	"os"
	"path/filepath"
	"testing"
)

func writeTestZip(t *testing.T, zipPath string, members map[string]string) {
	t.Helper()
	f, err := os.Create(zipPath)
	if err != nil {
		t.Fatal(err)
	}
	defer f.Close()
	zw := zip.NewWriter(f)
	for name, body := range members {
		w, err := zw.Create(name)
		if err != nil {
			t.Fatal(err)
		}
		if _, err := w.Write([]byte(body)); err != nil {
			t.Fatal(err)
		}
	}
	if err := zw.Close(); err != nil {
		t.Fatal(err)
	}
}

// A .zddc.zip dropped at any directory mounts a policy subtree there: its
// own-level member governs that directory, its "*"/named members govern
// descendants, and inherit:false makes it a self-contained island that ignores
// the ancestor cascade + embedded site defaults.
func TestZddcZipMountedAtSubtree(t *testing.T) {
	root := t.TempDir()
	// Site root: project_team has a member; embedded defaults apply below.
	if err := os.WriteFile(filepath.Join(root, ".zddc"),
		[]byte("roles:\n  project_team:\n    members: [team@x]\n"), 0o644); err != nil {
		t.Fatal(err)
	}
	for _, d := range []string{"Proj/special", "Proj/normal"} {
		if err := os.MkdirAll(filepath.Join(root, filepath.FromSlash(d)), 0o755); err != nil {
			t.Fatal(err)
		}
	}

	// Drop a self-contained island at /Proj/special (inherit:false) granting
	// only *@vendor.com, with a "*" descendant rule (read-only below).
	// A complete island fences both layers: top-level inherit:false drops the
	// embedded defaults + ancestor paths: contributions, and acl.inherit:false
	// clamps the ACL level-walk so ancestor levels' grants don't leak in.
	writeTestZip(t, filepath.Join(root, "Proj", "special", ".zddc.zip"), map[string]string{
		".zddc":   "inherit: false\nacl:\n  inherit: false\n  permissions:\n    \"*@vendor.com\": rwcd\n",
		"*/.zddc": "acl:\n  permissions:\n    \"*@vendor.com\": r\n",
	})
	InvalidateCache(root)

	verbs := func(dir, email string) VerbSet {
		chain, err := EffectivePolicy(root, filepath.Join(root, filepath.FromSlash(dir)))
		if err != nil {
			t.Fatalf("EffectivePolicy %s: %v", dir, err)
		}
		return EffectiveVerbs(chain, email)
	}

	// Bundle root member governs /Proj/special.
	if v := verbs("Proj/special", "u@vendor.com"); !v.Has(VerbC) || !v.Has(VerbW) || !v.Has(VerbD) {
		t.Errorf("/Proj/special vendor verbs = %v, want rwcd", v)
	}
	// Bundle's */.zddc governs a (virtual) descendant — read-only, deepest-wins.
	if v := verbs("Proj/special/anychild", "u@vendor.com"); !v.Has(VerbR) || v.Has(VerbW) {
		t.Errorf("/Proj/special/anychild vendor verbs = %v, want r only", v)
	}
	// inherit:false fences the site defaults: the embedded project-level
	// project_team grant has NO effect inside the island.
	if v := verbs("Proj/special", "team@x"); v != 0 {
		t.Errorf("/Proj/special team verbs = %v, want none (fenced island)", v)
	}
	// Outside the island, the embedded project-level grant still applies.
	if v := verbs("Proj/normal", "team@x"); !v.Has(VerbR) {
		t.Errorf("/Proj/normal team verbs = %v, want r (embedded project_team:r)", v)
	}
}
