package zddc

import (
	"archive/zip"
	"bytes"
	"embed"
	"io/fs"
	"strings"
	"sync"
)

// defaultsTreeFS is the embedded per-depth default policy tree — the source of
// truth for the shipped baseline, the bottom of every cascade. `all:` includes
// the `.zddc` (dot) files and `_any_` (underscore) directories a bare
// //go:embed would skip. The `_any_` directory is the on-disk stand-in for the
// "*" wildcard segment (kept out of literal "*" directories in the repo).
//
//go:embed all:defaults
var defaultsTreeFS embed.FS

// EmbeddedDefaultsZip packages the embedded per-depth default policy tree as a
// .zddc.zip with member paths using the "*" wildcard. The show-defaults CLI
// emits this so an operator can drop it at <ZDDC_ROOT>/.zddc.zip — or any
// directory — and edit, add, or delete individual members. Mounting it
// (optionally with inherit:false + acl.inherit:false to fully replace the
// baseline) is how a deployment customizes the shipped policy.
func EmbeddedDefaultsZip() ([]byte, error) {
	var buf bytes.Buffer
	zw := zip.NewWriter(&buf)
	err := fs.WalkDir(defaultsTreeFS, "defaults", func(p string, d fs.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if d.IsDir() {
			return nil
		}
		member := strings.ReplaceAll(strings.TrimPrefix(p, "defaults/"), AnyPlaceholder+"/", "*/")
		data, err := fs.ReadFile(defaultsTreeFS, p)
		if err != nil {
			return err
		}
		w, err := zw.Create(member)
		if err != nil {
			return err
		}
		_, err = w.Write(data)
		return err
	})
	if err != nil {
		return nil, err
	}
	if err := zw.Close(); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

var (
	embeddedTreeOnce sync.Once
	embeddedTree     PolicyTree
	embeddedTreeErr  error
)

// EmbeddedPolicyTree returns the baked-in per-depth default policy tree,
// memoised. The embedded form of the .zddc.zip mounted at the deployment root.
func EmbeddedPolicyTree() (PolicyTree, error) {
	embeddedTreeOnce.Do(func() {
		embeddedTree, embeddedTreeErr = LoadPolicyTreeFromFS(defaultsTreeFS, "defaults")
	})
	return embeddedTree, embeddedTreeErr
}

var (
	embeddedDefaultsOnce sync.Once
	embeddedDefaults     ZddcFile
	embeddedDefaultsErr  error
)

// EmbeddedDefaults returns the embedded defaults assembled from the per-depth
// tree into the single nested ZddcFile the cascade walker consumes, memoised.
//
// The cascade walker (EffectivePolicy) consults this as the bottom-most level
// unless an on-disk .zddc / .zddc.zip up the chain sets `inherit: false`.
func EmbeddedDefaults() (ZddcFile, error) {
	embeddedDefaultsOnce.Do(func() {
		tree, err := EmbeddedPolicyTree()
		if err != nil {
			embeddedDefaultsErr = err
			return
		}
		embeddedDefaults = tree.Assemble()
	})
	return embeddedDefaults, embeddedDefaultsErr
}
